Mr.100
Mr.100

Reputation: 151

Calling sem_post before sem_wait in multithreaded environment

The behavior of the sem_post() function is not clear for a binary semaphore based implementation.

What happens when you call sem_wait() after calling sem_post()? Will it work?

Code example :

Thread 1 :

do_something_critical()
sem_post();

Thread 2 :

sem_wait()
Proceed()

Here if some how sem_post() gets called before the call to sem_wait(), will it work? Or is it necessary that sem_wait() need to be called before sem_post()?

Upvotes: 0

Views: 4257

Answers (1)

Rachid K.
Rachid K.

Reputation: 5201

sem_post() merely increments the semaphore and wakes up any waiting thread if any. Otherwise it does nothing.

sem_wait() merely decrements the semaphore. The caller will be blocked only if the current value of the semaphore is 0.

Here is an example program where the main thread initializes a semaphore to 0 and calls sem_trywait() to verify that the semaphore is busy (i.e. value is 0). Then, it calls sem_post() to release the semaphore (i.e. value is 1) before creating a thread. The thread calls sem_wait() (this decrements the semaphore to 0) and returns. The main thread waits for the end of the thread and verifies that the semaphore is 0 with a call to sem_trywait():

#include <pthread.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <stdio.h>
#include <errno.h>

static sem_t *sem;

void *thd_entry(void *p)
{
int rc;

  printf("Thread is starting...\n");

  // This decrements the semaphore
  rc = sem_wait(sem);
  if (0 != rc) {
    perror("sem_wait()");
    return NULL;
  }

  printf("Thread is exiting...\n");

  return NULL;

}

int main(int ac, char *av[])
{
int        rc;
pthread_t  thd;

  // Create a semaphore with an initial value set to 0
  sem = sem_open("/example", O_CREAT|O_RDWR, 0777, 0);
  if (sem == SEM_FAILED) {
    perror("sem_open()");
    return 1;
  }

  // After creation the value of the semaphore is 0
  rc = sem_trywait(sem);
  if (-1 == rc) {
    if (errno == EAGAIN) {
      printf("Semaphore is busy (i.e. value is 0)\n");
    } else {
      perror("sem_trywait()");
      return 1;
    }
  }

  // Increment the semaphore
  rc = sem_post(sem);
  if (0 != rc) {
    perror("sem_post()");
    return 1;
  }

  // Create a thread
  rc = pthread_create(&thd, NULL, thd_entry, 0);
  if (0 != rc) {
    errno = rc;
    perror("pthread_create()");
    return 1;
  }

  rc = pthread_join(thd, NULL);
  if (0 != rc) {
    errno = rc;
    perror("pthread_join()");
    return 1;
  }

  // The semaphore is 0 as the thread decremented it
  rc = sem_trywait(sem);
  if (-1 == rc) {
    if (errno == EAGAIN) {
      printf("Semaphore is busy (i.e. value is 0)\n");
    } else {
      perror("sem_trywait()");
      return 1;
    }
  }

  return 0;
}

Here is a try:

$ ls -l /dev/shm
total 0
$ gcc sema.c -o sema -lpthread
$ ./sema 
Semaphore is busy (i.e. value is 0)
Thread is starting...
Thread is exiting...
Semaphore is busy (i.e. value is 0)
$ ls -l /dev/shm
total 4
-rwxrwxr-x 1 xxxxx xxxxx 32 janv.   5 16:24 sem.example
$ rm /dev/shm/sem.example

Upvotes: 2

Related Questions