15

In the man page it appears that even if you initialise a semaphore to a value of one:

sem_init(&mySem, 0, 1);

It could still be incremented to a value greater than 1 with multiple calls to

sem_post(&mySem);

But in this code example the comment seems to think differently:

sem_init(&mutex, 0, 1);      /* initialize mutex to 1 - binary semaphore */

Is it possible to initialise a strictly binary semaphore in C?

Note: The reason for doing this instead of using a mutex in this case is the sem_post and sem_wait may be called by different threads.

3 Answers 3

12

If you want a strictly binary semaphore on Linux, I suggest building one out of mutexes and condition variables.

struct binary_semaphore {
    pthread_mutex_t mutex;
    pthread_cond_t cvar;
    bool v;
};

void mysem_post(struct binary_semaphore *p)
{
    pthread_mutex_lock(&p->mutex);
    if (p->v)
        abort(); // error
    p->v = true;
    pthread_cond_signal(&p->cvar);
    pthread_mutex_unlock(&p->mutex);
}

void mysem_wait(struct binary_semaphore *p)
{
    pthread_mutex_lock(&p->mutex);
    while (!p->v)
        pthread_cond_wait(&p->cvar, &p->mutex);
    p->v = false;
    pthread_mutex_unlock(&p->mutex);
}
Sign up to request clarification or add additional context in comments.

11 Comments

What exactly is the point of the while loop in mysem_wait? Won't a simple if-statement do the job since pthread_cond_wait will reaquire the mutex after being signaled and pthread_cond_signal only unblocks a single thread waiting on the condition?
@BillDeRose: Condition variables are subject to spurious wakeups and stolen wakeups. You must use them in a loop if you want to check for a condition.
@DietrichEpp I can't understand, supose that you call wait before calling post. p->mutex is locked so if you call sem_post the thread will lock in sem_post and everything will locked (I'm sure that I'm wrong but I don't get it)If pthread_cond_signal unlock the mutex, why do you use additional mutex unlock
@Mquinteiro: Read the manual page for pthread_cond_wait. It unlocks the mutex while it is waiting. I don’t see any extra mutex unlock here, each call to lock() is paired with a call to unlock() at the end of the function.
@DietrichEpp that means that when is signaled and wait the finish p->mutex is locked again?
|
0

you can create a wrapper function for sem_post that will check the semaphore value before sem_post().

example:

int semaphore_give(sem_t *sem)
{
    int value, ret;

    if (!sem)
        return -1;
    
    if (sem_getvalue(sem, &value))
        return -1;

    if (value == 0)
        return sem_post(sem);
    return -1;
}

Comments

-1

I don't like the implementation of semaphores in Linux but have to use it. To make it simple I decrement sem value till zero with sem_trywait if it is returned one on the first check:

if (sem_trywait(pProcess->sem_id) < 0 && errno != EINTR ) {
    return ERROR;
}
else {
    while (sem_trywait(pProcess->sem_id) == 0);
    return OK;
}

Be careful if sem_post is called too often. You can stuck in the while() clause. In my case it's called no more than once per second.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.