У меня есть производитель и потребитель. Производитель заполняет свою внутреннюю очередь объектами, потребитель принимает эти объекты один за другим. Я хочу синхронизировать cosumer с производителем, чтобы потребитель блокировался, когда нет готовых объектов, и я хочу синхронизировать производителя с самим собой, чтобы он прекращал производство, когда очередь заполнена (и запускалась снова, когда есть место) . Как я могу это сделать? Я смог решить более простой случай без очереди, используя NSConditionalLock, но с очередью проблема выглядит более сложной.

0
zoul 9 Окт 2010 в 12:40

2 ответа

Лучший ответ

В итоге я использовал два семафора, objectsReady и bufferFreeSlots:

@implementation Producer

- (id) getNextObject {
    [objectsReady wait];
    id anObject = [[buffer objectAtIndex:0] retain];
    [buffer removeObjectAtIndex:0];
    [bufferFreeSlots signal];
    return [anObject autorelease];
}

- (void) decodeLoop {
    while (1) {
        [bufferFreeSlots wait];
        [buffer push:[self produceAnObject]];
        [objectsReady signal];
    }
}

@end

bufferFreeSlots инициализируется максимальным размером очереди. Пока что вроде работает, но Бог знает, что это акт веры, а не твердой уверенности.

0
zoul 11 Окт 2010 в 11:48

Вы можете рассмотреть возможность использования пары NSOperationQueues или очередей отправки. Попросите ваши производственные операции (в очереди производителя) отправлять сообщения в основном потоке, если это необходимо, объекту, который добавляет операции потребления в очередь потребителя.

1
Peter Hosey 9 Окт 2010 в 20:48
Мне нужно, чтобы производитель остановился, когда буфер заполнен (например, содержит четыре объекта), и запустил, когда снова появится место. Семафоры прекрасно об этом позаботятся. Могу ли я сделать то же самое с очередью на отправку?
 – 
zoul
9 Окт 2010 в 20:51
Я не уверен, что вы имеете в виду под «буфером»; ты про очередь операций потребления? Вы можете установить максимальное количество операций NSOperationQueue; он будет выполнять не более этого количества операций одновременно. Я не думаю, что вы можете сделать это с помощью GCD.
 – 
Peter Hosey
10 Окт 2010 в 04:44
Производитель обычно быстрее потребителя, поэтому я держу очередь созданных объектов. Я хочу, чтобы эта очередь оставалась небольшой из-за нехватки памяти. Это означает, что производитель должен остановиться, когда эта очередь станет достаточно большой, и возобновить работу, как только потребитель выберет объект из очереди. Максимальное количество операций очереди, похоже, в этом не помогает.
 – 
zoul
10 Окт 2010 в 11:10
1
Zoul: вы можете наблюдать за operationCount очереди потребителей и приостанавливать очередь производителя, когда она становится слишком высокой, и отменять ее, когда она возвращается к удобному уровню.
 – 
Peter Hosey
10 Окт 2010 в 11:30