POSIX Semaphores on Mac OS X: sem_timedwait alternative
It's likely that the timeout is important to the operation of the algorithm. Therefore just using sem_wait()
might not work.
You could use sem_trywait()
, which returns right away in all cases. You can then loop, and use a sleep interval that you choose, each time decrementing the total timeout until you either run out of timeout or the semaphore is acquired.
A much better solution is to rewrite the algorithm to use a condition variable, and then you can use pthread_cond_timedwait()
to get the appropriate timeout.
Yet another alternative may be to use the sem_timedwait.c implementation by Keith Shortridge of the Australian Astronomical Observatory's software group.
From the source file:
/** s e m _ t i m e d w a i t** Function:* Implements a version of sem_timedwait().** Description:* Not all systems implement sem_timedwait(), which is a version of* sem_wait() with a timeout. Mac OS X is one example, at least up to* and including version 10.6 (Leopard). If such a function is needed,* this code provides a reasonable implementation, which I think is* compatible with the standard version, although possibly less* efficient. It works by creating a thread that interrupts a normal* sem_wait() call after the specified timeout.** ...** Limitations:** The mechanism used involves sending a SIGUSR2 signal to the thread* calling sem_timedwait(). The handler for this signal is set to a null* routine which does nothing, and with any flags for the signal * (eg SA_RESTART) cleared. Note that this effective disabling of the* SIGUSR2 signal is a side-effect of using this routine, and means it* may not be a completely transparent plug-in replacement for a* 'normal' sig_timedwait() call. Since OS X does not declare the* sem_timedwait() call in its standard include files, the relevant * declaration (shown above in the man pages extract) will probably have* to be added to any code that uses this.* * ...* * Copyright (c) Australian Astronomical Observatory.* Commercial use requires permission.* This code comes with absolutely no warranty of any kind.*/
I used to use named semaphores on OSX, but now sem_timedwait isn't available and sem_init and friends are deprecated. I implemented semaphores using pthread mutex and conditions as follows which work for me (OSX 10.13.1). You might have to make a handle vs struct table and look up the sem_t type if it can't hold a ptr in it (i.e. pointers are 64bits and sem_t is 32?)
#ifdef __APPLE__typedef struct{ pthread_mutex_t count_lock; pthread_cond_t count_bump; unsigned count;}bosal_sem_t;int sem_init(sem_t *psem, int flags, unsigned count){ bosal_sem_t *pnewsem; int result; pnewsem = (bosal_sem_t *)malloc(sizeof(bosal_sem_t)); if (! pnewsem) { return -1; } result = pthread_mutex_init(&pnewsem->count_lock, NULL); if (result) { free(pnewsem); return result; } result = pthread_cond_init(&pnewsem->count_bump, NULL); if (result) { pthread_mutex_destroy(&pnewsem->count_lock); free(pnewsem); return result; } pnewsem->count = count; *psem = (sem_t)pnewsem; return 0;}int sem_destroy(sem_t *psem){ bosal_sem_t *poldsem; if (! psem) { return EINVAL; } poldsem = (bosal_sem_t *)*psem; pthread_mutex_destroy(&poldsem->count_lock); pthread_cond_destroy(&poldsem->count_bump); free(poldsem); return 0;}int sem_post(sem_t *psem){ bosal_sem_t *pxsem; int result, xresult; if (! psem) { return EINVAL; } pxsem = (bosal_sem_t *)*psem; result = pthread_mutex_lock(&pxsem->count_lock); if (result) { return result; } pxsem->count = pxsem->count + 1; xresult = pthread_cond_signal(&pxsem->count_bump); result = pthread_mutex_unlock(&pxsem->count_lock); if (result) { return result; } if (xresult) { errno = xresult; return -1; }}int sem_trywait(sem_t *psem){ bosal_sem_t *pxsem; int result, xresult; if (! psem) { return EINVAL; } pxsem = (bosal_sem_t *)*psem; result = pthread_mutex_lock(&pxsem->count_lock); if (result) { return result; } xresult = 0; if (pxsem->count > 0) { pxsem->count--; } else { xresult = EAGAIN; } result = pthread_mutex_unlock(&pxsem->count_lock); if (result) { return result; } if (xresult) { errno = xresult; return -1; } return 0;}int sem_wait(sem_t *psem){ bosal_sem_t *pxsem; int result, xresult; if (! psem) { return EINVAL; } pxsem = (bosal_sem_t *)*psem; result = pthread_mutex_lock(&pxsem->count_lock); if (result) { return result; } xresult = 0; if (pxsem->count == 0) { xresult = pthread_cond_wait(&pxsem->count_bump, &pxsem->count_lock); } if (! xresult) { if (pxsem->count > 0) { pxsem->count--; } } result = pthread_mutex_unlock(&pxsem->count_lock); if (result) { return result; } if (xresult) { errno = xresult; return -1; } return 0;}int sem_timedwait(sem_t *psem, const struct timespec *abstim){ bosal_sem_t *pxsem; int result, xresult; if (! psem) { return EINVAL; } pxsem = (bosal_sem_t *)*psem; result = pthread_mutex_lock(&pxsem->count_lock); if (result) { return result; } xresult = 0; if (pxsem->count == 0) { xresult = pthread_cond_timedwait(&pxsem->count_bump, &pxsem->count_lock, abstim); } if (! xresult) { if (pxsem->count > 0) { pxsem->count--; } } result = pthread_mutex_unlock(&pxsem->count_lock); if (result) { return result; } if (xresult) { errno = xresult; return -1; } return 0;}#endif