Я работаю над созданием очереди блокировки, к которой одновременно получают доступ около 10 рабочих потоков.Базовая реализация очереди выглядит следующим образом:
-(void) enqueue:(__strong id)value
{
[_mutex lock];
while ([self size] == _maxSize) {
[_mutex wait];
}
[_queue enqueue:value];
[_mutex signal];
[_mutex unlock];
}
-(id) dequeue
{
[_mutex lock];
while ([self isEmpty]) {
[_mutex wait];
}
id value = [_queue dequeue];
[_mutex broadcast];
[_mutex unlock];
return value;
}
Где _mutex
- это NSCondition
.Проблемы возникают при использовании методов -isEmpty
и -size
:
-(int) size
{
@try {
[_mutex lock];
return [_queue size];
}
@finally {
[_mutex unlock];
}
}
-(BOOL) isEmpty
{
@try {
[_mutex lock];
return [_queue isEmpty];
}
@finally {
[_mutex unlock];
}
}
Поскольку им требуется блокировка мьютекса, чтобы убедиться в отсутствии повреждения данных, это ставит программу в тупик,поскольку NSCondition
не блокируется рекурсивно.Однако, если я изменю свою реализацию на следующее:
-(void) enqueue:(__strong id)value
{
while ([self size] == _maxSize) {
[_mutex lock];
[_mutex wait];
[_mutex unlock];
}
[_mutex lock];
[_queue enqueue:value];
[_mutex signal];
[_mutex unlock];
}
-(id) dequeue
{
while ([self isEmpty]) {
[_mutex lock];
[_mutex wait];
[_mutex unlock];
}
[_mutex lock]; // when I require the lock here, another thread has already dequeued the object
id value = [_queue dequeue];
[_mutex broadcast];
[_mutex unlock];
return value;
}
Тогда программа не заходит в тупик, однако к тому времени, когда я повторно получу блокировку, другой работник уже заберет нужный мне объект.Есть мысли о том, как сделать NSCondition
рекурсивным?