Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Don't use dispatch semaphores where mutexes (or dispatch queues) would suffice. Apple platforms have a QOS mechanism that donates priority from higher-QOS threads to lower ones when they're waiting on locks that the higher-QOS thread owns, but with semaphores the system doesn't know what thread "owns" the semaphore and so it can't donate priority. Mutexes (and dispatch queues), including os_unfair_lock, will donate priority accordingly.

Which is to say, dispatch semaphores shouldn't be used if you're initializing them with a value of 1, you should only use them if you have an actual pool of resources you're protecting.



Semaphores are for signaling (sames a condition variables, events) while mutexes are for mutual exclusion. Technically you can also use semaphores for mutual exclusion (a mutex can be thought as a binary semaphore) but you really shouldn't.


Right, but libdispatch doesn't have a mutex. It has semaphores and queues. So if you're trying to use libdispatch and you don't want the closure-based aspect of queues, you might be tempted to use a semaphore instead. Don't do that, use os_unfair_lock or pthread_mutex (or a higher-level construct like NSLock) instead.


I was hazy on remembering details for my comment above, but I now realize fully that I do have experience with semaphores on Darwin. It went like this:

First I tried POSIX semaphores. They seemed poorly done on Darwin. [Maybe they needed sem_open() rather than sem_init()? But unnamed ones are way more useful!]

Then I tried Mach semaphores.

Then I saw a recommendation for libdispatch semaphores to avoid too many syscalls.

Given that Linux does the syscall-avoiding trick by default for standard-conforming semaphores, it seems to me like on Darwin you can't go too far wrong always using libdispatch. But I guess you miss that priority inversion workaround you were talking about.


On Apple platforms the simple set of guidelines would look something like:

* Can you use dispatch_queue? Great, use it.

* If not, can you use pthread_mutex? Note that this can be configured to be unfair if desired. If so, use it.

* If not (e.g. you need actual semaphore behavior), use dispatch_semaphore.

os_unfair_lock is more of an optimization when speed is a must. It's a replacement for the old OSSpinLock, but AFAICT it basically acts like a normal mutex under contention, so I'm not actually sure why pthread_mutex would be preferred over it, except the documentation says to prefer pthread or libdispatch as they're "higher level" primitives.

Also of interest is dispatch_group_t, which is basically an inverted semaphore (it counts active tasks, and lets you wait until all tasks have completed). Under the hood it's actually a semaphore that's initialized with LONG_MAX as the value and some custom logic (including atomics) around waiting.


Yeah, obviously if I needed a mutex I would use a mutex, I don't have that particular confusion and would expect pthread mutex to be well worn on the platform. (And I noticed Darwin has some helpful pthread_mutex_attr values.) I am talking only about the case where you really want a semaphore.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: