Apple doc's GCD Producer-Consumer solution wrong? Apple doc's GCD Producer-Consumer solution wrong? multithreading multithreading

Apple doc's GCD Producer-Consumer solution wrong?


In the solution decribed at that Apple document:

  1. There is no buffer because no buffer is needed;
  2. System load is the bound;
  3. Consumers are tasks.

Say you have multiple producers and consumers, producers place data in a shared buffer and consumers read data from that shared buffer. A semaphore or monitor is used to synchronise access to the shared buffer, and the buffer size is fixed so as to limit the amount of data that are being produced according to the rate they’re being consumed, hence throttling the producer.

Under Grand Central Dispatch, consumers are tasks dispatched to a queue. Since tasks are Objective-C blocks, a producer doesn’t need a buffer to tell a consumer about the data it should process: Objective-C blocks automatically capture objects they reference.

For example:

// Producer implementationwhile (…) {    id dataProducedByTheProducer;    // Produce data and place it in dataProducedByTheProducer    dataProducedByTheProducer = …;    // Dispatch a new consumer task    dispatch_async(queue, ^{        // This task, which is an Objective-C block, is a consumer.        //        // Do something with dataProducedByTheProducer, which is        // the data that would otherwise be placed in the shared        // buffer of a traditional, semaphore-based producer-consumer        // implementation.        //        // Note that an Objective-C block automatically keeps a        // strong reference to any Objective-C object referenced        // inside of it, and the block releases said object when        // the block itself is released.        NSString *s = [dataProducedByTheProducer …];    });}

The producer may place as many consumer tasks as data it can produce. However, this doesn’t mean that GCD will fire the consumer tasks at the same rate. GCD uses operating system information to control the amount of tasks that are executed according to the current system load. The producer itself isn’t throttled, and in most cases it doesn’t have to be because of GCD’s intrinsic load balancing.

If there’s actual need to throttle the producer, one solution is to have a master that would dispatch n producer tasks and have each consumer notify the master (via a task that’s dispatched after the consumer has finished its job) that it has ended, in which case the master would dispatch another producer task. Alternatively, the consumer itself could dispatch a producer task upon completion.

Specifically answering the items you’ve addressed:

The Producer-Consumer problem is also known as the Bounded-Buffer problem, yet the above makes no mention of a buffer

A shared buffer isn’t needed because consumers are Objective-C blocks, which automatically capture data that they reference.

its bound

GCD bounds the number of dispatched tasks according to the current system load.

or the consumer

Consumers are the tasks dispatched to GCD queues.

let alone blocking the producer & consumer in order to avoid over/under runs

There’s no need for blocking since there’s no shared buffer. As each consumer is an Objective-C block capturing the produced data via the Objective-C block context capturing mechanism, there’s a one-to-one relation between consumer and data.