Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to lock an NSLock on a specific thread

I have a property @property NSLock *myLock

And I want to write two methods:

- (void) lock

and

- (void) unlock

These methods lock and unlock myLock respectively and they need to do this regardless of what thread or queue called them. For instance, thread A might have called lock but queue B might be the one calling unlock. Both of these methods should work appropriately without reporting that I am trying to unlock a lock from a different thread/queue that locked it. Additionally, they need to do this synchronously.

like image 991
Nosrettap Avatar asked Apr 11 '13 15:04

Nosrettap


People also ask

Can you lock a thread?

For a thread to work on an object, it must have control over the lock associated with it, it must “hold” the lock. Only one thread can hold a lock at a time. If a thread tries to take a lock that is already held by another thread, then it must wait until the lock is released.

Does NSLock block the thread?

Yes, it's safe to use NSLock from any thread, including the main thread. The only constraint with NSLock is that you must unlock it from the same thread that you locked it, which you are doing here.

What does it mean for a thread to be locked?

A locked thread is a forum thread that does not allow new comments. Threads can only be locked by moderators or (as of 2019) by the Discourse system account.

What is NSRecursiveLock?

NSRecursiveLock defines a lock that may be acquired multiple times by the same thread without causing a deadlock, a situation where a thread is permanently blocked waiting for itself to relinquish a lock.


1 Answers

It is rare anymore that NSLock is the right tool for the job. There much better tools now, particularly with GCD; more later.

As you probably already know from the docs, but I'll repeat for those reading along:

Warning: The NSLock class uses POSIX threads to implement its locking behavior. When sending an unlock message to an NSLock object, you must be sure that message is sent from the same thread that sent the initial lock message. Unlocking a lock from a different thread can result in undefined behavior.

That's very hard to implement without deadlocking if you're trying to lock and unlock on different threads. The fundamental problem is that if lock blocks the thread, then there is no way for the subsequent unlock to ever run on that thread, and you can't unlock on a different thread. NSLock is not for this problem.

Rather than NSLock, you can implement the same patterns with dispatch_semaphore_create(). These can be safely updated on any thread you like. You can lock using dispatch_semaphore_wait() and you can unlock using dispatch_semaphore_signal(). That said, this still usually isn't the right answer.

Most resource contention is best managed with an operation queue or dispatch queue. These provide excellent ways to handle work in parallel, manage resources, wait on events, implement producer/consumer patterns, and otherwise do almost everything that you would have done with an NSLock or NSThread in the past. I highly recommend the Concurrency Programming Guide as an introduction to how to design with queues rather than locks.

like image 129
Rob Napier Avatar answered Oct 01 '22 14:10

Rob Napier