Inter-process communication : Unix systems
The following is my first article and shouldn’t be taken too seriously. I’m a french computer science student and the piece you’re about to read is part of an assessment. Enjoy !
Inter-process communication : a brief reminder
The first release of the System V UNIX operating system, developed by AT&T UNIX Support Group (USG), is published in 1983. This system brings along a few features, like the curse library, the vi editor, or, plot twist, the support for inter-process communication (let’s switch to IPC).
IPC simply allows processes to share data. When a process is running (see below), it has its own memory-space and its own resources (variables — functions…).
Sometimes, a user may want processes to communicate, to share data or to perform actions together. This is the very purpose of IPC.
Lemipc : let’s take a look
The lemipc is a two week Epitech project which tackle the concept of concurrent accesses. The goal is to fight players on a two dimensions game board. When a player is surrounded, it dies. 3 IPC methods are explored within this project :
Shared memory : shared memory is a memory block that can be accessed simultaneously by multiple processes. The project’s game board will be stored in a shared memory segment, so that the players have a common area to evolve.
Semaphores : A semaphore is used to control access to a shared resource. In our case, we need to protect the board. When a player wants to access a cell, we have to be sure that this cell is available.
Message queue : The players need to have a certain strategy : each player can communicate with its team. To do that, we’ll use a message queue. A process can send or receive a message, which will make our players smarter (or less dumb)
Let’s talk code
Now that we have a better understanding of IPC, let’s see some code. The project contains only one binary. The first call will create the shared memory segment, and all the other calls will add a player to the game, with the specified team id. I use the return value to check if the resources are already created. Do not forget to check the errno variable
First of all, System V IPC relative functions need a key to work. We’ll use the ftok() function.
#include <sys/ipc.h>
...
key_t key;
char *path = "/valid/path";
int project_id = 42;key = ftok(path, project_id);if (key == -1)
// error
We now have our key, it’s time to create the shared memory segment :
#include <sys/shm.h>
#include <sys/types.h>
...
int shm_id;
void *addr;// we try to access the segment
shm_id = shmget(key, size, SHM_R | SHM_W);
if (shm_id == -1) // if it doesn't exist, we create it
{
if (errno)
// error
shm_id = shmget(key, size, IPC_CREAT | SHM_R | SHM_W);
}// we now store the segment address !
addr = shmat(lemme->shm_id, NULL, SHM_R | SHM_W);
We have our board ! We now need to secure it with a semaphore. To create or to access a semaphore, we use the exact same code as before, with the semget() function :
#include <sys/sem.h>
...
int sem_id;// we only need 1 semaphore
sem_id = semget(key, 1, SHM_R | SHM_W);
if (sem_id == -1)
{
if (errno)
// error
sem_id = semget(key, 1, IPC_CREAT | SHM_R | SHM_W);
semctl(sem_id, 0, SETVAL, 1);
}
Our semaphore can now be used. It acts like a counter. When its value is 0, the resource, our board, is locked. To change the counter’s value, we use a structure and a function, semop() :
struct sembuf sops;
sops.sem_num = 0;
sops.sem_flg = 0;
sops.sem_op = op; // 1 or -1, to increase or decrease the counter
semop(sem_id, &sops, 1);
We need to perform this operation every time we want to access the board. The execution is simple : lock — check / modify the board — unlock.
Our players can now access to a protected game board. Since we didn’t have the time to create a powerful AI, they can only perform a few basic actions:
Their default comportment is to rush toward the center. If a player encounters an enemy, it will send a message to its team, ordering the other players to come and help. To create or use a message queue, we need to use the msgget() function, which has the same behavior as the others :
#include <sys/msg.h>
...
int msg_id;msg_id = msgget(key, SHM_R | SHM_W);
if (msg_id == -1)
{
if (errno)
// error
msg_id = msgget(key, IPC_CREAT | SHM_R | SHM_W);
}
Let’s now see how to send or receive a message :
typedef struct s_msg
{
long mtype; // the message type, our team number
char mtext[MSGSZ]; // the message text, our positions
} t_msg;// We use a t_msg-like structure to send information.
// The IPC_NOWAIT flag allows the execution to continue
// if no message is received.msgsnd(msg_id, &msg, sizeof(msg), IPC_NOWAIT);msgrcv(msg_id, msg, sizeof(*msg), team_number, IPC_NOWAIT);
So… Here we are… players can communicate, the game can start !
The final product
Here are some screens about the different steps of our game. Just a nice and awesome SFML graphical view of our board.
As expected, the players are heading toward the center :
To sum up !
This was a cool project ! IPC is a very interesting notion, not so hard to understand. We had at first a few troubles to implement the message queue, because we didn’t know what to do with them. Anyway, it was fun !
I hope you have enjoyed reading this. It was my first article, and my English is not fluent, but I tried ! Don’t hesitate to correct my mistakes, the comment section is below :D Here’s a list of useful links, related of course to IPC :
http://www.tldp.org/pub/Linux/docs/ldp-archived/linuxfocus/English/Archives/lf-2003_01-0281.pdf
https://en.wikipedia.org/wiki/Inter-process_communication
Thanks !