UNIX & GNU/Linux - System calls - Using semget()

Today a tutorial to learn how to use semget(), semctl() and semop() system calls.

What are these functions?
 
They help to share data and control access to these data.
One calls them semaphore.
 
We can for example use them to access a data from different process.
In the example below, we will create two process with the same code, except for the  sb.sem_op value.
For the first program the value will be 1 and for the second, this value will be -1.
 
So when we will run the both program in a different terminal (different process then), we will increase the result by 1 or decrease the same result by 1.
 
If you decrease below 0 with the first program, it will never display the result.
But if you increase just by 1 the result with the second program, the first program will be back and display the result.
 
So, let's create our 2 programs:

1. The first program: semaphore1.c

 

/* semaphore1.c */

#include <errno.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <sys/ipc.h>

#include <sys/shm.h>

#include <sys/sem.h>

#include <sys/types.h>


int main(int ac, char *av[])

{

key_t key;

int sem_id;

void *addr;

struct sembuf sb;


if (ac != 2)

printf("Usage %s pathname\n", av[0]);

if ((key = ftok(av[1], 0)) == -1)

fprintf(stderr, "Error: '%s'. %s\n", av[1], strerror(errno));

else

printf("key = %d\n", key);



sem_id = semget(key, 2, SHM_R | SHM_W);


if (sem_id == -1)

{

sem_id = semget(key, 2, IPC_CREAT | SHM_R | SHM_W);

printf("sem_id = %d\n", sem_id);

semctl(sem_id, 0, SETVAL, 10);

}

else

{

printf("sem_id already created -> %d\n", sem_id);

sb.sem_num = 0;

sb.sem_flg = 0;

sb.sem_op = -1;

semop(sem_id, &sb, 1);

printf("Value = %d\n", semctl(sem_id, 0, GETVAL));

}

return (EXIT_SUCCESS);

}
 
 

2. The second program: semaphore2.c

 
/* semaphore2.c */

#include <errno.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <sys/ipc.h>

#include <sys/shm.h>

#include <sys/sem.h>

#include <sys/types.h>


int main(int ac, char *av[])

{

key_t key;

int sem_id;

void *addr;

struct sembuf sb;


if (ac != 2)

printf("Usage %s pathname\n", av[0]);

if ((key = ftok(av[1], 0)) == -1)

fprintf(stderr, "Error: '%s'. %s\n", av[1], strerror(errno));

else

printf("key = %d\n", key);



sem_id = semget(key, 2, SHM_R | SHM_W);


if (sem_id == -1)

{

sem_id = semget(key, 2, IPC_CREAT | SHM_R | SHM_W);

printf("sem_id = %d\n", sem_id);

semctl(sem_id, 0, SETVAL, 10);

}

else

{

printf("sem_id already created -> %d\n", sem_id);

sb.sem_num = 0;

sb.sem_flg = 0;

sb.sem_op = 1;

semop(sem_id, &sb, 1);

printf("Value = %d\n", semctl(sem_id, 0, GETVAL));

}

return (EXIT_SUCCESS);

}
 

3. Let's play with them

Let's compile our both program:

$ gcc semaphore1.c -o sem1
$ gcc semaphore2.c -o sem2

We can now open 2 terminals (2 windows) to test that we can interact on the same data with 2 different process.

In the first terminal, execute the first :

$ ./sem1 /home 

The result will be something like that:

 

key = 327682

sem_id = 393216
Re run it:
 
$ ./sem1 /home 
Now you have:
 
key = 327682

sem_id already created -> 393216

Result = 9
Things important are that the key and sem_id are the same.
The result is now 9, because at the beginning we were 10.
So 10 - 1 = 9.
 
Let's run it again 10 times.
And what we have is this:
key = 327682
sem_id already created -> 393216

This time the Result isn't displayed and the program is in infinite loop.
Let's open the second terminal, compile and execute the program:
$ gcc semaphore2.c -o sem2 ; ./sem2 /home
It happens two things.
 
1. In the second terminal:
key = 327682
sem_id already created -> 393216
Result = 0
2. The first terminal finish and come back to the prompt.
 
We can now decrease the result by 1 with the first program and increase this result by 1 with the second.
Interesting, isn't it? cool

Add new comment

Plain text

  • No HTML tags allowed.
  • Lines and paragraphs break automatically.