IOS SDK - сообщение NSLock: "разблокировано из потока, который не заблокировал его"

Я получаю эту ошибку, используя NSLock, которую я пытался обойти, используя unlockWithCondition (используя NSConditionLock), но независимо от этого я получаю тот же результат:

* Перерыв на _NSLockError() для отладки. * - [NSLock unlock]: блокировка ( '(null)') разблокирована из потока, который не заблокировал его.

Я не уверен, что это плохо, но я делаю так:

new Thread:
[lockA lock];//waiting unlock
[lockB lock];//waiting unlock
..shared code..
[lockA unlock];
[lockB unlock];

in Main Thread:
//Do two HTTP request.

//when request respond, I unlock the locks in respective threads with [lockA unlock];
[lockB unlock];

Таким образом, раздел "... общий код.." может выполняться. Я не понимаю, почему я получаю эту ошибку.

Может кто-нибудь объяснить, что я делаю не так? Похоже, это должно работать идеально.

2 ответа

Решение

Я думаю, что вы пытаетесь использовать замки в качестве семафоров здесь. Блокировки предназначены для того, чтобы остановить фоновый поток и основной поток от одновременного доступа к чему-либо. Следовательно, нить, удерживающая блокировку, должна также разблокировать (разблокировать) ее.

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

Используйте семафоры GCD для удобных и простых семафоров: https://developer.apple.com/library/ios/#documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html

Если вы выполняете свои HTTP-запросы на NSURLConnection или аналогичном и пытаетесь разблокировать его в делегате, вам нужно быть осторожным, когда вы создаете и инициируете NSURLConnection, так как он должен вернуться в этот поток, если вы явно не используете scheduleInRunLoop:mode поместить его в другой поток или запустить цикл.

Если вы уверены, что блокируете основной поток, вы должны разблокировать этот поток. Чтобы вернуться туда, вы можете использовать либо performSelectorOnMainThread:withObject:waitUntilDone: обратный вызов или GCD для обратного вызова в главном потоке, используя:

  dispatch_async(dispatch_get_main_queue(), ^(void) {
       ...
    });

С вашими разблокировками в... пространстве. Вы могли бы использовать dispatch_sync() вместо этого, если вам нужно знать, что разблокировка завершена, прежде чем двигаться дальше.

Однако, используя NSConditionLock, как вы указали, вы уже попробовали это решение. Тем не менее, вам все равно нужно сделать блокировку в потоке поиска, а не в основном потоке. Условие будет охраняться вашим -unlockWithCondition: используя определенное условие, поэтому он не будет разблокирован до того, как поисковый поток пометит его как готовый.

Итак, в вашем основном потоке запустите поисковые потоки. В каждой поисковой теме -lock а затем приступить к извлечению данных, затем -unlockWithContidition:, В потребительской ветке используйте -lockWhenCondition и ты должен быть в порядке.

Ключ в том, что вы должны заблокировать и разблокировать один и тот же поток.

Другие вопросы по тегам