2015-03-04 2 views
2

В последнее время я использую NSCondition, и я действительно не понимаю блокировку и разблокировку.Работа замка NSCondition

Например,

NSCondition lock = [NSCondition new]; 

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
    //Do stuff 
    [lock signal]; 
}; 

[lock wait]; 
//Do rest 

Это работает отлично. Какая разница в этом.

NSCondition lock = [[NSCondition alloc] init]; 
[lock lock]; 

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
    //Do stuff 
    [lock signal]; 
    [lock unlock]; 
}; 

[lock wait]; 
//Do rest 

ответ

3

Перед ожиданием вы должны удерживать блокировку переменной состояния. Ожидание отпускает блокировку, затем гарантируется блокировка до тех пор, пока она не будет сигнализирована, и блокировка была повторно принята. Обратите внимание, что если несколько потоков ждут, только один будет уведомлен о сигнале, остальные будут продолжать ждать дальнейших сигналов. В качестве альтернативы, если предикат останется истинным после выполнения, тогда сигнал может быть передан всем потокам.

Блокировка - это блокировка взаимного исключения (mutex), что означает, что только один поток может удерживать блокировку в любой момент времени. Помимо использования этого для защиты того, что вы используете для переменной условия, оно также защищает внутренние действия переменной условия. Если вы попытаетесь использовать его без блокировки, тогда будут условия гонки при проверке/установке условия для нескольких потоков.

Для правильного использования переменной условия, ни один из ваших примеров верен. Все дело в том, чтобы защитить состояние предиката. Вот пример, основанный на псевдокоде от the documentation.

NSCondition condvar = [NSCondition new]; 
__block BOOL workRequired = NO; 

// something somewhere else does this at some point ^{ 
    [condvar lock]; 
    workRequired = YES; 
    [condvar signal]; 
    [condvar unlock]; 
}; 

[condvar lock]; 

while (!workRequired) { 
    [condvar wait]; 
} 

// Do the work 
workRequired = NO; 
[condvar unlock]; 

В вашем примере у вас нет никаких условий, кроме «законченного блока». В этом случае вам следует просто использовать dispatch_sync.

dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
    // Do stuff 
}; 

// Do rest 

Если по каким-то причинам вы не знаете, если вы уже работаете в этой очереди, то semaphore будет достаточно.

dispatch_semaphore_t semaphore = dispatch_semaphore_create(0L); 

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
    // Do stuff 
    dispatch_semaphore_signal(semaphore); 
}; 

dispatch_semaphore_wait(semaphore); 
// Do rest 
+0

В дополнение к проблемам, которые вы отметили, OP блокируется на одном потоке и разблокируется на другом, что не является законным. –

Смежные вопросы