4 ms·
Can anybody explain the advantages or otherwise of Apple’s libdispatch for locking? I understand there’s Linux support now also. Is this something you would use
by dhsysusbsjsi 7y ago
Can anybody explain the advantages or otherwise of Apple’s libdispatch for locking? I understand there’s Linux support now also. Is this something you would use outside of Apple ecosystem?
https://developer.apple.com/documentation/dispatch/dispatch_semaphore?language=objc https://developer.apple.com/documentation/dispatch/dispatch_...
- asveikau 7y agoQuoting from the link: > A dispatch semaphore is an efficient implementation of a traditional counting semaphore. Dispatch semaphores call down to the kernel only when the calling thread needs to be blocked. If the calling semaphore does not need to block, no kernel call is made. This sounds like the same optimization that futex(2) makes for pthread mutex on Linux. So while a naive semaphore might enter the kernel 100% of the time, this one does so only when there is actual waiting to do. It would seem to me that sem_wait() does similar on glibc so Linux probably performs similarly with the standard POSIX semaphore: > https://github.com/bminor/glibc/blob/master/nptl/sem_wait.c https://github.com/bminor/glibc/blob/master/nptl/sem_wait.c mirrored from here: > https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=blob;f=nptl/sem_wait.c;h=171716fdbce243d64a9da46acdc4dc77d81921b4;hb=HEAD https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=blob;f=n...
- lilyball 7y agoDon'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.
- gpderetta 7y agoSemaphores 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.
- lilyball 7y agoRight, 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.
- asveikau 7y agoI 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.
- lilyball 7y agoOn 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.
- gok 7y agoIt's a different programming paradigm. Libdispatch is really meant to be a form of coroutine-oriented asynchronous serialization. It can be used for synchronous locking but it's not particularly good at it.