A semaphore is nothing more than a variable that is protected. It provides a means to restrict access to a resource that is shared amongst two or more processes. Two operations are permitted, commonly called acquire and release. The acquire operation allows a process to take the semaphore, and if it has already been acquired, then the process blocks until it’s available. If a process has the semaphore, it can release it, which allows other processes to acquire it. The process of releasing a semaphore automatically wakes up the next process awaiting it on the acquire operation.
The Type of Semaphore
The binary semaphore
represents a single resource, and therefore when one process has acquired it, others are blocked until it is released.
The counting semaphore
is used to represent shared resources in quantities greater than one.
The Head Files and Linux APIs:
#include
<sys/types.h>
#include
<sys/ipc.h>
#include
<sys/sem.h>
int
semget( key_t key, int nsems, int semflg );
int
semop( int semid, struct sembuf *sops, unsigned int nsops );
int
semctl( int semid, int semnum, int cmd, ... );
User Utilities
GNU/Linux provides the ipcs command to explore semaphores from the command line.
# ipcs –s
This presents all the semaphores that are visible to the calling process.
# ipcs -s -i semid
We can get extended information about the semaphore using the -i option.
Creating a Semaphore
#include
<stdio.h>
#include
<sys/sem.h>
#include
<stdlib.h>
int
main()
{
int semid;
/* Create the semaphore with the id MY_SEM_ID */
semid = semget( MY_SEM_ID, 1, 0666 | IPC_CREAT );
if (semid >= 0)
printf( "semcreate: Created a semaphore %d/n", semid );
return 0;
}
Getting a Semaphore
#include
<stdio.h>
#include
<sys/sem.h>
#include
<stdlib.h>
int
main()
{
int semid;
struct sembuf sb;
/* Get the semaphore with the id MY_SEM_ID */
semid = semget( MY_SEM_ID, 1, 0 );
if (semid >= 0)
{
sb.sem_num = 0;
sb.sem_op = -1;
sb.sem_flg = 0;
printf( "semacq: Attempting to acquire semaphore %d/n", semid );
/* Acquire the semaphore */
if
( semop( semid, &sb, 1 ) == -1 )
{
printf( "semacq: semop failed./n" );
exit(-1);
}
printf( "semacq: Semaphore acquired %d/n", semid );
}
return 0;
}
Releasing a Semaphore
#include
<stdio.h>
#include
<sys/sem.h>
#include
<stdlib.h>
int
main()
{
int semid;
struct sembuf sb;
/* Get the semaphore with the id MY_SEM_ID */
semid = semget( MY_SEM_ID, 1, 0 );
if (semid >= 0)
{
printf( "semrel: Releasing semaphore %d/n", semid );
sb.sem_num = 0;
sb.sem_op = 1;
sb.sem_flg = 0;
/* Release the semaphore */
if
(semop( semid, &sb, 1 ) == -1)
{
printf("semrel: semop failed./n");
exit(-1);
}
printf( "semrel: Semaphore released %d/n", semid );
}
return 0;
}
Retrieving the Current Semaphore Count
int
main()
{
int semid, cnt;
/* Get the semaphore with the id MY_SEM_ID */
semid = semget( MY_SEM_ID, 1, 0 );
if (semid >= 0)
{
/* Read the current semaphore count */
cnt = semctl( semid, 0, GETVAL );
if (cnt != -1)
printf("semcrd: current semaphore count %d./n", cnt);
}
return 0;
}
Setting the Current Semaphore Count
#include
<stdio.h>
#include
<sys/sem.h>
#include
<stdlib.h>
int
main()
{
/* Get the semaphore with the id MY_SEM_ID */
int
semid = semget( MY_SEM_ID, 1, 0 );
if (semid >= 0)
{
/* Set the current semaphore count */
ret = semctl( semid, 0, SETVAL, 6 );
if (ret != -1)
printf( "semcrd: semaphore count updated./n" );
}
return 0;
}
Removing a Semaphore
#include
<stdio.h>
#include
<sys/sem.h>
#include
<stdlib.h>
int
main()
{
/* Get the semaphore with the id MY_SEM_ID */
int
semid = semget( MY_SEM_ID, 1, 0 );
if (semid >= 0)
{
int ret = semctl( semid, 0, IPC_RMID);
if (ret != -1)
printf( "Semaphore %d removed./n", semid );
}
return 0;
}
Another Example
#include
<stdio.h>
#include
<stdlib.h>
#include
<sys/types.h>
#include
<unistd.h>
#include
<sys/ipc.h>
#include
<sys/sem.h>
#include
<sys/types.h>
int main()
{
int semid = semget( 0x33333, 1, 0666|IPC_CREAT );
if( semid >= 0)
printf("sem 33 created: %d/n", semid);
sembuf sb;
int ret = fork();
if( ret == 0 ) ////child process:
{
printf("child 1 active/n");
//get sem:
//sembuf sb;
int semid1 = semget( 0x33333, 1, 0);
if( semid1 >= 0 )
{
printf("attempt to acquire sem %d/n", semid1 );
sb.sem_num = 0;
sb.sem_op = -1;
sb.sem_flg = 0;
if( semop( semid , &sb, 1 ) == -1 )
printf( "semop error in child process/n");
// we have the sem:
printf("child 1 get the sem/n");
}
exit(0);
}
// main process:
printf( "main process release sem/n" );
sb.sem_num = 0;
sb.sem_op = 1;
sb.sem_flg = 0;
semop( semid , &sb, 1 );
printf("main process exit/n");
return 0;
}
ref:GNU/Linux Application Programming