3

I´m getting this error using NSLock which I tried to circumvent by using unlockWithCondition (using NSConditionLock), but regardless I get the same result:

* Break on _NSLockError() to debug. * -[NSLock unlock]: lock ( '(null)') unlocked from thread which did not lock it.

I´m not sure if it´s bad, but what I´m doing is this:

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];

So the section "..shared code.." can execute. I don´t understand why i´m getting this error.

Can anyone explain what I´m doing wrong? It´s look like it should work perfectly.

ZiggyST
  • 587
  • 6
  • 11

2 Answers2

7

I think you're trying to use locks as semaphores here. Locks are meant to stop the background thread and the main thread from accessing something simultaneously. Hence, the thread holding the lock must release (unlock) it too.

If you want the background thread to wait for something to happen on the main thread, use semaphores.

Use GCD semaphores for nice and easy semaphores: https://developer.apple.com/library/ios/#documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html

Steven Kramer
  • 8,473
  • 2
  • 37
  • 43
1

If you are doing your HTTP requests on NSURLConnection or similar and trying to unlock in the delegate, you need to be careful where you create and initiate the NSURLConnection from, as it should return to that thread, unless you explicitly use scheduleInRunLoop:mode to put it on another thread or run loop.

If you are certain that you're locking on the main thread, you should be unlocking on that thread. To get back there, you can use either performSelectorOnMainThread:withObject:waitUntilDone: callback or GCD to call back on the main thread using:

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

With your unlocks in the ... space. You could use dispatch_sync() instead if you need to know the unlocks have completed before moving on.

However, using NSConditionLock, as you'd indicated you'd already tried is the solution. However, you still need to do the lock on the retrieval thread, not on the main thread. The condition will be guarded by your -unlockWithCondition: using a specific condition, so it won't unlock prior to the retrieval thread marking it as ready.

So, in your main thread, launch the retrieval threads. In each retrieval thread, -lock and then proceed to retrieve the data, then -unlockWithContidition:. In the consumer thread, use -lockWhenCondition and you should be fine.

The key is, though, that you have to lock and unlock on the same thread.

gaige
  • 17,263
  • 6
  • 57
  • 68
  • Thanks a lot for your answer, I´m not unlocking on the same thread, why this is an issue? it´s the usual functionality of the locks.., make something wait to other for be ready – ZiggyST Mar 01 '12 at 20:43
  • OK, seeing that you'd already tried NSCondition lock, I added comments above about how to do so without running into that error. – gaige Mar 03 '12 at 16:24
  • Thanks for the answer, but i can´t lock it from the thread who unlock it. What i do: i need two different values coming from different HHTP request, so do the request, and lock the function witch need both values(in another thread using performSelectorInBackground:), then when request response, i parse them on different threads, and when they finish parse, i unlock the NSlock, so the other thread can procede to use those values. PD: using NSconditionLock, i´m having the same error messages. – ZiggyST Mar 05 '12 at 15:24
  • I think you misunderstood. You don't need to lock on the thread to prevent the other thread from getting the lock too early. That's done by changing the condition value. That's the benefit of using the NSConditionLock. If you lock on thread one, then unlockWithCondition: 2 on thread one, you then is lockOnCondition:2 on thread 2 to lock the NSConditionLock there and continue. When done, unlockWithCondition: 3 and then the lockUponCondition: 3 on the next thread to wait for that one to finish. It creates the sequencing you want without locking and unlocking on separate threads – gaige Mar 06 '12 at 21:10