1.Introduction to Semaphores
Semaphores can be thought of as simple counters that indicate the status of a resource. This counter is a protected variable and cannot be accessed by the user directly. The shield to this variable is provided by none other than the kernel. The usage of this semaphore variable is simple. If counter is greater that 0, then the resource is available, and if the counter is 0 or less, then that resource is busy or being used by someone else. This simple mechanism helps in synchronizing multithreaded and multiprocess based applications. Semaphores were invented and proposed by Edsger Dijkstra, and still used in operating systems today for synchronization purposes. The same mechanism is now available for application developers too. Its one of the most important aspects of interprocess communication.
[smartads] [smartads]
Semaphores can be either binary or counting, depending on the number of shared resources. If a single shared resource is used, then we would require just one semaphore for synchronization purposes. In that case, the semaphore is referred as a binary semaphore. In all other cases, where the number of resources shared across users are greater than one, you would use multiple semaphores, in which case they are referred as counting semaphores.
Semaphores basically implement two kinds of operations. One to wait on the semaphore variable and another that signals the semaphore variable.
2. Semaphore Control
This program demonstrates the use of semaphores to solve the critical region problem.
int sem_init(sem_t *sem, int pshared, unsigned int value);
The sem_init() function is used to initialize the semaphore’s value. The pshared argument must be 0 for semaphores local to a process.
int sem_wait(sem_t * sem);
The sem_wait() function performs the equivalent of the down semaphore operation.
int sem_post(sem_t * sem);
The sem_post() function performs the equivalent of the up semaphore operation.
int sem_destroy(sem_t * sem);
The sem_destroy() function is used to properly deallocate resources alloted to a semaphore. The semaphore in this program is used as a mutex, a binary semaphore, to implement mutual exclusion between two processes which use a shared resource.
To compile and link the program:
gcc -o sem-ex sem-ex.c -Wall -Werror -lpthread
3.Semaphore Example
/* Includes */ #include <unistd.h> /* Symbolic Constants */ #include <sys/types.h> /* Primitive System Data Types */ #include <errno.h> /* Errors */ #include <stdio.h> /* Input/Output */ #include <stdlib.h> /* General Utilities */ #include <pthread.h> /* POSIX Threads */ #include <string.h> /* String handling */ #include <semaphore.h> /* Semaphore */ /* prototype for thread routine */ void handler ( void *ptr ); /* global vars */ /* semaphores are declared global so they can be accessed in main() and in thread routine, here, the semaphore is used as a mutex */ sem_t mutex; int counter; /* shared variable */ int main() { int i[2]; pthread_t thread_a; pthread_t thread_b; i[0] = 0; /* argument to threads */ i[1] = 1; sem_init(&mutex, 0, 1); /* initialize mutex to 1 - binary semaphore */ /* second param = 0 - semaphore is local */ /* Note: you can check if thread has been successfully created by checking return value of pthread_create */ pthread_create (&thread_a, NULL, (void *) &handler, (void *) &i[0]); pthread_create (&thread_b, NULL, (void *) &handler, (void *) &i[1]); pthread_join(thread_a, NULL); pthread_join(thread_b, NULL); sem_destroy(&mutex); /* destroy semaphore */ /* exit */ exit(0); } /* main() */ void handler ( void *ptr ) { int x; x = *((int *) ptr); printf("Thread %d: Waiting to enter critical region...\n", x); sem_wait(&mutex); /* down semaphore */ /* START CRITICAL REGION */ printf("Thread %d: Now in critical region...\n", x); printf("Thread %d: Counter Value: %d\n", x, counter); printf("Thread %d: Incrementing Counter...\n", x); counter++; printf("Thread %d: New Counter Value: %d\n", x, counter); printf("Thread %d: Exiting critical region...\n", x); /* END CRITICAL REGION */ sem_post(&mutex); /* up semaphore */ pthread_exit(0); /* exit thread */ }