1. Introduction
POSIX fournit plusieurs mécanismes permettant à des processus de communiquer ou de se synchroniser entre eux.
Ces mécanismes sont appelés IPC, pour Inter-Process Communication.
Les IPC POSIX ont été introduits comme une alternative aux mécanismes IPC System V.
Les trois principaux mécanismes IPC POSIX sont :
- Les files de messages POSIX.
- Les sémaphores POSIX.
- La mémoire partagée POSIX.
2. Les trois mécanismes IPC POSIX
2.1 Les files de messages POSIX
Les files de messages permettent à plusieurs processus d'échanger des messages.
Contrairement à un pipe, les données ne forment pas obligatoirement un simple flux continu d'octets.
Chaque message possède sa propre frontière.
Par exemple, si un processus envoie deux messages :
Code: Select all
"START"
Code: Select all
"STOP"
Les principales fonctions sont :
Code: Select all
mq_open()
mq_close()
mq_unlink()
mq_send()
mq_receive()
Code: Select all
mq_getattr()
mq_setattr()
mq_notify()
Priorité des messages
Une particularité importante des files de messages POSIX est la possibilité d'attribuer une priorité à chaque message.
Un message de priorité élevée peut être récupéré avant un message de priorité plus faible.
Cela permet donc de gérer facilement des messages urgents.
3. Les sémaphores POSIX
3.1 Principe
Les sémaphores servent principalement à synchroniser plusieurs threads ou plusieurs processus.
Un sémaphore POSIX contient une valeur entière qui ne peut pas devenir négative.
Deux opérations fondamentales sont utilisées :
Code: Select all
sem_wait()
sem_post()
sem_wait()
sem_wait() tente de décrémenter la valeur du sémaphore.
Si la valeur est supérieure à 0, elle est décrémentée immédiatement.
Si la valeur vaut 0, le thread ou le processus appelant est bloqué jusqu'à ce qu'une ressource devienne disponible.
sem_post()
sem_post() incrémente la valeur du sémaphore.
Cette opération peut réveiller un thread ou un processus bloqué dans sem_wait().
Exemple conceptuel
Sémaphore initialisé à :
Code: Select all
1
Code: Select all
sem_wait()
Code: Select all
1 -> 0
Processus B appelle ensuite :
Code: Select all
sem_wait()
B est donc bloqué.
Lorsque A termine :
Code: Select all
sem_post()
Code: Select all
0 -> 1
4. Sémaphores nommés et non nommés
POSIX fournit deux catégories de sémaphores.
Sémaphores nommés
Ils possèdent un nom et peuvent être utilisés facilement entre plusieurs processus indépendants.
Ils sont créés ou ouverts avec :
Code: Select all
sem_open()
Code: Select all
sem_close()
Code: Select all
sem_unlink()
Sémaphores non nommés
Ils sont directement stockés dans une zone mémoire.
Ils utilisent notamment :
Code: Select all
sem_init()
sem_destroy()
5. Mémoire partagée POSIX
5.1 Principe
La mémoire partagée permet à plusieurs processus d'accéder à une même zone mémoire.
C'est généralement l'un des mécanismes IPC les plus rapides.
Au lieu d'envoyer les données à travers le noyau à chaque échange, plusieurs processus peuvent mapper le même objet mémoire dans leur espace d'adressage virtuel.
Création de l'objet
La fonction principale est :
Code: Select all
shm_open()
Exemple :
Code: Select all
int fd = shm_open("/shared_mem", O_CREAT | O_RDWR, 0666);
Dimension de l'objet
Après la création, l'objet possède généralement une taille qui doit être définie.
On utilise pour cela :
Code: Select all
ftruncate()
Code: Select all
ftruncate(fd, 4096);
Mapping
La mémoire peut ensuite être mappée dans l'espace virtuel du processus avec :
Code: Select all
mmap()
Code: Select all
void *ptr = mmap(
NULL,
4096,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fd,
0
);
MAP_SHARED
MAP_SHARED signifie que les modifications réalisées dans la zone mappée sont visibles par les autres processus ayant mappé le même objet.
6. Nommage des objets IPC POSIX
Les objets IPC POSIX nommés utilisent généralement un nom commençant par :
Code: Select all
/
Code: Select all
"/myqueue"
"/mysem"
"/shared_mem"
Le noyau utilise ce nom pour identifier l'objet IPC.
Exemples
File de messages :
Code: Select all
mq_open("/queue", ...);
Code: Select all
sem_open("/sem", ...);
Code: Select all
shm_open("/memory", ...);
7. Création et ouverture d'un objet IPC
Les interfaces POSIX utilisent souvent une logique ressemblant à open().
Par exemple :
Code: Select all
mq_open()
sem_open()
shm_open()
O_CREAT
O_CREAT demande de créer l'objet s'il n'existe pas déjà.
Exemple :
Code: Select all
shm_open("/memory", O_CREAT | O_RDWR, 0666);
O_EXCL
O_EXCL est généralement utilisé avec O_CREAT.
Si l'objet existe déjà, l'opération échoue.
Exemple :
Code: Select all
shm_open(
"/memory",
O_CREAT | O_EXCL | O_RDWR,
0666
);
8. Permissions
Lors de la création d'un objet IPC POSIX, on peut souvent fournir des permissions similaires aux permissions des fichiers Unix.
Exemple :
Code: Select all
0666
- lecture + écriture pour le propriétaire ;
- lecture + écriture pour le groupe ;
- lecture + écriture pour les autres.
9. Descripteurs et handles
Les mécanismes POSIX n'utilisent pas tous exactement le même type de handle.
La mémoire partagée retourne un descripteur de fichier classique :
Code: Select all
int fd;
Code: Select all
int fd = shm_open(...);
Code: Select all
mqd_t
Code: Select all
mqd_t queue = mq_open(...);
Code: Select all
sem_t *
Code: Select all
sem_t *sem = sem_open(...);
10. Suppression d'un objet IPC
Fermer un objet et supprimer son nom sont deux opérations différentes.
C'est un principe important des IPC POSIX.
File de messages
Fermer :
Code: Select all
mq_close()
Code: Select all
mq_unlink()
Sémaphore nommé
Fermer :
Code: Select all
sem_close()
Code: Select all
sem_unlink()
Mémoire partagée
Fermer le descripteur :
Code: Select all
close()
Code: Select all
shm_unlink()
11. Principe de unlink
unlink ne signifie pas nécessairement que l'objet disparaît immédiatement.
Il supprime son nom.
Les processus qui possèdent déjà une référence valide vers l'objet peuvent généralement continuer à l'utiliser.
L'objet sera réellement détruit lorsque les références restantes auront disparu.
Ce comportement ressemble au fonctionnement de unlink() avec les fichiers Unix.
12. Comparaison avec System V IPC
System V possède lui aussi :
- des files de messages ;
- des sémaphores ;
- de la mémoire partagée.
System V
On rencontre notamment :
Code: Select all
msgget()
msgsnd()
msgrcv()
semget()
semop()
semctl()
shmget()
shmat()
shmdt()
shmctl()
Ils peuvent également utiliser des clés de type :
Code: Select all
key_t
POSIX
On utilise plutôt :
Code: Select all
mq_open()
mq_send()
mq_receive()
sem_open()
sem_wait()
sem_post()
shm_open()
mmap()
13. Différence importante concernant les sémaphores
Les sémaphores System V peuvent être organisés en ensembles de plusieurs sémaphores.
Une opération semop() peut également effectuer des opérations plus complexes sur ces ensembles.
Avec POSIX, un objet sem_t représente directement un sémaphore individuel.
Cela rend souvent l'utilisation plus simple.
System V
Code: Select all
semget()
semop()
semop() permet de réaliser des opérations sur ces sémaphores.
POSIX
Chaque sem_t représente essentiellement un sémaphore.
Les opérations principales sont :
Code: Select all
sem_wait()
sem_post()
14. Différence concernant les files de messages
Avec System V, les messages possèdent généralement un champ :
Code: Select all
long mtype;
Exemple System V
Code: Select all
struct message {
long mtype;
char data[128];
};
Chaque message peut recevoir une priorité.
Exemple :
Code: Select all
mq_send(queue, buffer, size, priority);
15. Différence concernant la mémoire partagée
Avec System V :
Code: Select all
shmget()
Puis :
Code: Select all
shmat()
Avec POSIX
Code: Select all
shm_open()
Puis :
Code: Select all
mmap()
Cette approche s'intègre donc directement au mécanisme général de mapping mémoire Unix.
16. Exemple minimal de mémoire partagée POSIX
Code: Select all
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
int main(void)
{
int fd = shm_open(
"/demo",
O_CREAT | O_RDWR,
0666
);
if (fd == -1) {
perror("shm_open");
return EXIT_FAILURE;
}
if (ftruncate(fd, 4096) == -1) {
perror("ftruncate");
close(fd);
return EXIT_FAILURE;
}
char *ptr = mmap(
NULL,
4096,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fd,
0
);
if (ptr == MAP_FAILED) {
perror("mmap");
close(fd);
return EXIT_FAILURE;
}
strcpy(ptr, "Inside The System");
munmap(ptr, 4096);
close(fd);
shm_unlink("/demo");
return EXIT_SUCCESS;
}
17. Étapes générales d'utilisation
Le fonctionnement général d'un objet IPC POSIX nommé ressemble souvent à ceci :
- Donner un nom à l'objet.
- Créer ou ouvrir l'objet.
- Configurer l'objet si nécessaire.
- Utiliser l'objet pour communiquer ou se synchroniser.
- Fermer la référence locale.
- Supprimer le nom de l'objet lorsqu'il n'est plus nécessaire.
Exemple mémoire partagée
Code: Select all
shm_open()
↓
ftruncate()
↓
mmap()
↓
lecture / écriture
↓
munmap()
↓
close()
↓
shm_unlink()
Exemple file de messages
Code: Select all
mq_open()
↓
mq_send() / mq_receive()
↓
mq_close()
↓
mq_unlink()
Exemple sémaphore nommé
Code: Select all
sem_open()
↓
sem_wait() / sem_post()
↓
sem_close()
↓
sem_unlink()
18. Avantages des IPC POSIX
Les IPC POSIX possèdent plusieurs avantages :
- API généralement plus homogène.
- Utilisation de noms lisibles pour les objets nommés.
- Intégration naturelle avec certaines API Unix classiques.
- shm_open() fonctionne avec mmap().
- Les files de messages possèdent un système de priorité.
- Les sémaphores POSIX sont relativement simples à manipuler.
- L'interface est standardisée par POSIX.
19. Points importants à retenir
Les trois principales familles IPC POSIX sont :
- Message queues.
- Semaphores.
- Shared memory.
Code: Select all
mq_open()
mq_send()
mq_receive()
mq_close()
mq_unlink()
sem_open()
sem_wait()
sem_post()
sem_close()
sem_unlink()
shm_open()
ftruncate()
mmap()
munmap()
close()
shm_unlink()
Code: Select all
/
Code: Select all
"/inside_the_system"
O_EXCL combiné avec O_CREAT permet d'échouer si l'objet existe déjà.
Fermer un objet ne signifie pas nécessairement supprimer son nom.
Les opérations :
Code: Select all
mq_unlink()
sem_unlink()
shm_unlink()
La mémoire partagée POSIX utilise mmap(), contrairement à la mémoire partagée System V qui utilise principalement shmat().
Les sémaphores POSIX utilisent principalement sem_wait() et sem_post(), alors que System V utilise notamment semop().
Les files de messages POSIX utilisent des priorités, tandis que System V repose notamment sur le champ mtype.
20. Résumé
POSIX IPC est une famille de mécanismes de communication et de synchronisation entre processus.
Elle fournit :
- des files de messages ;
- des sémaphores ;
- de la mémoire partagée.
Par rapport à System V IPC, l'interface POSIX est souvent plus cohérente et plus facile à intégrer avec les autres mécanismes Unix.
Les chapitres suivants permettent ensuite d'étudier séparément et plus en profondeur les files de messages POSIX, les sémaphores POSIX et la mémoire partagée POSIX.
