while (_running) {
if ([tasks count] > 0)
{
NSArray *tasksCopy = nil;
@synchronized(tasks)
{
tasksCopy = [tasks copy];
[tasks removeAllObjects];
}
for (NSInvocation *invocation in tasksCopy)
{
[invocation invoke];
}
[tasksCopy release];
}
<...>
}
NSMutableArray
непотокобезопасен, но конкретно метод count
наверняка возвращает значение атомарно, что однако не означает потокобезопасности, т.е. например кодif ([tasks count] > 0){
[tasks removeObjectAtIndex:0];
}
count
, но не полностью завершил добавление элемента к моменту вызова removeObjectAtIndex:
).if ([tasks count] > 0)
за пределы блока синхронизации — это преждевременная оптимизация, в данном коде есть другие места, на что в первую очередь стоит обратить внимание.while (running){ }
будет при отсутствии задач постоянно нагружать процессор «пустыми» циклами, когда как нормальный event loop
— нет.NSRunLoop
Вам быть может и не обязателен, однако NSAutoreleasePool
— наверняка. Причем, т.к. NSAutoreleasePool
очищает себя по окончании каждого цикла event loop, которого у вас нет, то периодически создавать и очищать NSAutoreleasePool
нужно внутри цикла while(running)
.NSInvocation
для заданий несколько удивителен. Во-первых, это неудобно, гораздо удобнее использовать блоки, а во-вторых относительно медленно (что, в принципе наверняка не критично, надо профилировать). Вызов одного блока по времени занимает примерно столько же, сколько отправка одного сообщения, а вызов NSInvocation
в ~20 раз медленней. Правда, если в блоке использовать weak переменные, это будет примерно как NSInvocation
, но это не ваш случай, т.к. не используется ARC.