Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GCD vs @synchronized vs NSLock

Can someone give a rundown of the benefits and drawbacks of these 3 systems in how they relate to thread safety?

From watching more recent WWDC videos, I get the feeling that Apple is pushing the usage of GCD to create performant reader-writer that are thread safe.

What's the idea/backing behind this? Is it the time to access a lock having to enter the kernel that leads to this GCD push, and shying away from @synchronized and NSLock?

Are @synchronized and NSLock being pushed out of what would be considered best practice, or is there still a place for them?

like image 340
chris P Avatar asked Mar 19 '16 03:03

chris P


People also ask

What is NSLock?

An object that coordinates the operation of multiple threads of execution within the same application.

Is NSLock thread safe?

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.

Does NSLock block the thread?

An NSLock is a mutex; it prevents multiple threads from accessing the same resource simultaneously, which is exactly what you want to do here. Once one thread acquires the lock, other threads attempting to acquire the lock will wait until the first thread releases the lock.


1 Answers

There are many many details that could be discussed at great length in regards to this. But, at the core:

These always require a lock to be taken somewhere or somehow:

@synchronized(...) { ... }
[lock lock];

Locks are very expensive for the reasons you mention; they necessarily consume kernel resources. (The @synchronized() case actually may avoid kernel locks these days, but it is a hash based exclusion mechanism and that, in itself, is expensive).

And these do not always require a lock (but sometimes maybe do):

dispatch_sync(...concurrent q...., ^{ ... });
dispatch_async(...queue of any kind...., ^{ ... });

There is a fast path through the dispatch functions that are effectively lockless (though they will use test-and-set atomic primitives that can cause performance issues under load).

The end result is that a synchronous dispatch to a concurrent queue can effectively be treated as "execute this on this thread right now". A synchronous dispatch to a serial queue can do the atomic test-and-set to test if the queue is processing, mark it as busy, and, if it wasn't busy, execute the block on the calling thread immediately.

Asynchronous dispatches can be similarly as fast, though asynchronous dispatch requires copying the block (which can be very cheap, but something to think about).

In general, GCD can do anything a lock can do, can do it at least -- if not more -- efficiently, and you can use the GCD APIs to go way beyond just simple locking (using a semaphore as a computation throttle, for example).

BTW: If your tasks are relatively coarse grained, have a look at NSOperationQueue and NSOperation.

like image 86
bbum Avatar answered Nov 15 '22 09:11

bbum