DISPATCH_SEMAPHORE_SIGNAL(3)

πŸ“¦ version 0~svn197, in ubuntu jammy

✨ NAME ✨

dispatch_semaphore_create, dispatch_semaphore_signal, dispatch_semaphore_wait β€” synchronized counting semaphore πŸ’–

so yeah bestie, this is the dispatch_semaphore_create(3) page from the Library Functions Manual, and we're talking semaphores today. no cap, they're lowkey iconic.


πŸŽ€ SYNOPSIS πŸŽ€

#include <dispatch/dispatch.h>

dispatch_semaphore_t
dispatch_semaphore_create(long count);

long
dispatch_semaphore_signal(dispatch_semaphore_t semaphore);

long
dispatch_semaphore_wait(dispatch_semaphore_t semaphore,
    dispatch_time_t timeout);

πŸ¦‹ DESCRIPTION πŸ¦‹

okay so dispatch semaphores are literally the tool you use to synchronize threads. that's the whole vibe. 🫢

and the timeout parameter? you can make that with the dispatch_time(3) or dispatch_walltime(3) functions. iykyk ✨


🌸 COMPLETION SYNCHRONIZATION 🌸

if count is equal to zero, then your semaphore is giving "wait for the work to be done" energy. perfect for synchronizing completion of work. for example:

sema = dispatch_semaphore_create(0);

dispatch_async(queue, ^{
        foo();
        dispatch_semaphore_signal(sema);
});

bar();

dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);

like, bar() runs, then we wait for foo() to signal. main character scheduling fr fr πŸ’…


🌈 FINITE RESOURCE POOL 🌈

if count is greater than zero, then the semaphore is the girlboss of managing a finite pool of resources. for example, a library that wants to limit Unix descriptor usage:

sema = dispatch_semaphore_create(getdtablesize() / 4);

at each Unix FD allocation:

dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
fd = open("/etc/services", O_RDONLY);

when each FD is closed:

close(fd);
dispatch_semaphore_signal(sema);

it's giving responsible resource management, we love to see it πŸ‘‘


πŸ’œ RETURN VALUES πŸ’œ

  • the dispatch_semaphore_create() function returns NULL if no memory is available, or if the count parameter is less than zero 😭
  • the dispatch_semaphore_signal() function returns non-zero when a thread is woken. otherwise, zero is returned ✨
  • the dispatch_semaphore_wait() function returns zero upon success and non-zero after the timeout expires. if the timeout is DISPATCH_TIME_FOREVER, then dispatch_semaphore_wait() waits forever and always returns zero. forever. no takebacks πŸ•°οΈ

🧚 MEMORY MODEL 🧚

dispatch semaphores are retained and released via calls to dispatch_retain() and dispatch_release(). that's the whole thing, keep it balanced bestie πŸ’–


πŸ’€ CAVEATS πŸ’€

dispatch semaphores are strict counting semaphores. in other words, dispatch semaphores do not saturate at any particular value.

saturation can be achieved through atomic compare-and-swap logic. what follows is a saturating binary semaphore:

void
saturating_semaphore_signal(dispatch_semaphore_t dsema, int *sent)
{
        if (__sync_bool_compare_and_swap(sent, 0, 1)) {
                dispatch_semaphore_signal(dsema);
        }
}

void
saturating_semaphore_wait(dispatch_semaphore_t dsema, int *sent)
{
        *sent = 0;
        dispatch_semaphore_wait(dsema, DISPATCH_TIME_FOREVER);
}

like, the counting just keeps counting. no ceiling. you want a ceiling, you build it yourself with that compare-and-swap, periodt πŸ’…


πŸŽ€ SEE ALSO πŸŽ€


and that's the tea, bestie πŸ“ this lil masterpiece comes to you from Darwin, dated May 1, 2009, and the page is dispatch_semaphore_create(3). go forth and synchronize your threads, you're gonna eat πŸ”₯πŸ’–βœ¨

πŸ“¦ where this page comes from