SYSTEM V Semaphores in C using semget, semctl, semop system V system calls in Linux

In the previous chapter we learned about shared memory. And there is a problem of race condition when there are multiple process are trying to access and change the shared memory.

Now, we have 2 different API to use semaphores. System V semaphore are the older version and POSIX semaphore API which are newer version.

In this chapter we shall learn about System V semaphore.

So to solve this problem we should use semaphores to avoid the race condition.

We shall learn about semaphores by taking series of simple steps and then taking a full example.

1. How to get a System V semaphore?
————————————————————

To get a semaphore you need to use “semget()” system call.

The function prototype is:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int semget(key_t key, int nsems, int semflg);

Here:

key : It is a unique identifier, if any process wants to connect to the queue, it should have to use the same key.

As key is a “long” data type, you can use any integer to set the key.

Or you can also use “ftok()” known as “file to key”. The function accepts 2 arguments, first is file path and the next is a id. “ftok()” will use these 2 arguments and then will create a unique key. The other program trying to access this queue should use the same parameters.

Function prototype for ftok is:

key_t ftok(const char *path, int id);

nsems : It is the number of semaphores in the present semaphore set.

Below is the way to create a semaphore:

#include <sys/ipc.h>
#include <sys/sem.h>

key_t key;
int semid;

key = ftok("/home/aj/myFile", 'E');
semid = semget(key, 10, 0666 | IPC_CREAT);

Once a semaphore is created, they’re all uninitialized; to make them free, you need to use semop() or semctl(). We shall see in further in this chapter.

2. How to control a System V semaphore?
————————————————————

To control a semaphore use “semctl()” system call.

“semctl()” will allow to initialize a positive value the semaphores, to make the resources available.

It allows you set for individual semaphore or complete semaphore set.

Function prototype is:

int semctl(int semid, int semnum, int cmd, ... /*arg*/);
Here:
semid: It is the ID you get, when you call semget().
semnum:  It is the ID of the semaphore that needs to manipulate.
cmd: It is used to perform operations on the semaphore.
The “cmd” argument can be any one of the below:
GETVAL : Return the value of a given single semaphore.
SETVAL : Set the value of a single semaphore.
GETPID : Return the PID of the process that performed the last operation on the semaphore or array.
GETNCNT : Return the number of processes waiting for the value of a semaphore to increase.
GETZCNT : Return the number of processes waiting for the value of a particular semaphore to reach zero.
GETALL : Return the values for all semaphores in a set.
SETALL : Set values for all semaphores in a set.
IPC_STAT : Load status information about the semaphore set into the  struct semid_ds.
IPC_RMID : Remove the specified semaphore set.
arg: It needs to be a union senum. It is optional.
senum structure:
union semun {
    int val;               /* used for SETVAL only */
    struct semid_ds *buf;  /* used for IPC_STAT and IPC_SET */
    ushort *array;         /* used for GETALL and SETALL */
};

3. How to perform operations a System V semaphore?

To perform operations on a semaphore, you need to use semop() system call.
Syntax for semop():
int semop(int semid, struct sembuf *sops, unsigned int nsops);
Here:
semid: It is the ID you get, when you call semget().
sops:  It ss a pointer to the “struct sembuf” which is filled with semaphore commands.
If sem_op is negative, then its value is subtracted from the semaphore.
If sem_op is positive, then it’s value is added to the semaphore.
if sem_op is zero (0), then the calling process will sleep() until the semaphore’s value is 0

4. How to destroy a System V semaphore?

A semaphore can be destroyed by calling semctl() with the cmd IPC_RMID.
Example:
semctl(semid, 0, IPC_RMID);
Let us see an example for System V semaphore.
I have created 3 programs.
1. SemInit.c : It will create a semaphore.
2. SemDemo.c : It will use the semaphore that you have created. Run this in multiple windows.
3. SemRemove.c : It will remove the semaphore that you have created.
SemInit.c [Run this first]
#include <stdio.h> 
#include <stdlib.h> 
#include <errno.h> 
#include <sys/types.h> 
#include <sys/ipc.h> 
#include <sys/sem.h>

//for more tutorials on C, C++, STL, DS visit www.ProDeveloperTutorial.com

int main(void)
{
    key_t key;
    int semid;
    union semun arg;
    
    if ((key = ftok("semdemo.c", 'J')) == -1) 
    {   
        perror("ftok");
        exit(1); 
    }
    
/* create a semaphore set with 1 semaphore: */
    if ((semid = semget(key, 1, 0666 | IPC_CREAT)) == -1) 
    {
        perror("semget");
        exit(1); 
    }
/* initialize semaphore #0 to 1: */ arg.val = 1;
    if (semctl(semid, 0, SETVAL, arg) == -1) 
    {
        perror("semctl");
        exit(1); 
    }
return 0; 
    
}

SemDemo.c

#include <stdio.h> 
#include <stdlib.h> 
#include <errno.h> 
#include <sys/types.h> 
#include <sys/ipc.h> 
#include <sys/sem.h>

//for more tutorials on C, C++, STL, DS visit www.ProDeveloperTutorial.com

int main(void)
{
    key_t key;
    int semid;
    struct sembuf sb = {0, -1, 0}; /* set to allocate resource */
    if ((key = ftok("semdemo.c", 'J')) == -1) 
    {   perror("ftok");
        exit(1); 
    }
/* grab the semaphore set created by seminit.c: */ 
    if ((semid = semget(key, 1, 0)) == -1) 
    {
        perror("semget");
        exit(1); 
    }

    printf("Press return to lock: "); 
        getchar();
    printf("Trying to lock...\n");
    if (semop(semid, &sb, 1) == -1) 
    { 
        perror("semop");
        exit(1); 
    }
    
    printf("Locked.\n");
    printf("Press return to unlock: "); 
    getchar();
    
    sb.sem_op = 1; /* free resource */ 
    if (semop(semid, &sb, 1) == -1) 
    {
        perror("semop");
        exit(1); 
        
    }
    printf("Unlocked\n");
    return 0; 
    
}

SemRemove.c

#include <stdio.h> 
#include <stdlib.h> 
#include <errno.h> 
#include <sys/types.h> 
#include <sys/ipc.h> 
#include <sys/sem.h>

//for more tutorials on C, C++, STL, DS visit www.ProDeveloperTutorial.com

 int main(void)
{
    key_t key;
    int semid;
    union semun arg;

    if ((key = ftok("semdemo.c", 'J')) == -1) 
    { 
        perror("ftok");
        exit(1); 
    }
    
/* grab the semaphore set created by seminit.c: */ 
    if ((semid = semget(key, 1, 0)) == -1) 
    {
        perror("semget");
        exit(1); 
    }
    
/* remove it: */
    if (semctl(semid, 0, IPC_RMID, arg) == -1) 
    {
        perror("semctl");
        exit(1); 
    }
return 0; 
}
Write a Comment

Leave a Comment

Your email address will not be published. Required fields are marked *