Apple doc的GCD Producer-Consumer解决方案错了吗?

时间:2011-10-17 09:54:44

标签: ios multithreading macos grand-central-dispatch producer-consumer

在Apple的并发编程指南的“远离线程迁移”部分中,有 Changing Producer-Consumer Implementations,声称可以使用GCD简化典型的多步pthread互斥+条件变量实现。

  

使用调度队列,您可以简化生产者和消费者   实现为单个调用:

dispatch_async(queue, ^{
  // Process a work item.
});
  

当您的生产者要完成工作时,它所要做的就是将该工作添加到队列中并让队列处理该项目。

生产者 - 消费者问题也被称为有界缓冲问题,但上面没有提到缓冲区,它的界限或消费者,更不用说阻止生产者和放大器了。消费者,以避免过度/不足。

这怎么可能是一个有效的解决方案?

1 个答案:

答案 0 :(得分:22)

在Apple文件中描述的解决方案中:

  1. 没有缓冲区,因为不需要缓冲区;
  2. 系统负载是绑定的;
  3. 消费者是任务。
  4. 假设您有多个生产者和消费者,生产者将数据放在共享缓冲区中,而消费者从该共享缓冲区中读取数据。信号量或监视器用于同步对共享缓冲区的访问,并且缓冲区大小是固定的,以便根据它们消耗的速率限制正在生成的数据量,从而限制生产者。

    在Grand Central Dispatch下,消费者是派遣到队列的任务。由于任务是Objective-C块,生产者不需要缓冲区来告诉消费者它应该处理的数据:Objective-C块自动捕获它们引用的对象。

    例如:

    // Producer implementation
    while (…) {
        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 …];
        });
    }
    

    生产者可以放置与其可以生成的数据一样多的消费者任务。但是,这并不意味着GCD将以相同的速率启动消费者任务。 GCD使用操作系统信息来控制根据当前系统负载执行的任务量。生产者本身没有受到限制,在大多数情况下,它不一定是因为GCD的内在负载平衡。

    如果实际需要限制生产者,一个解决方案是让主人调度 n 生产者任务并让每个消费者通知主人(通过在消费者完成后调度的任务)它已经结束,在这种情况下,主人将派遣另一个生产者任务。或者,消费者本身可以在完成时派遣生产者任务。

    具体回答您已解决的问题:

      

    Producer-Consumer问题也称为Bounded-Buffer问题,但上面没有提到缓冲区

    不需要共享缓冲区,因为使用者是Objective-C块,它会自动捕获它们引用的数据。

      

    其约束

    GCD根据当前系统负载限制调度任务的数量。

      

    或消费者

    消费者是派遣到GCD队列的任务。

      

    更不用说阻止制片人了消费者,以避免过度/不足

    由于没有共享缓冲区,因此无需阻塞。由于每个使用者都是一个Objective-C块,通过Objective-C块上下文捕获机制捕获生成的数据,因此消费者和数据之间存在一对一的关系。