À l'aide de la fonction fork on peut créer de nouveaux processus
Exemples de communication :
kill)ls | grep toto)Il existe de nombreuses méthodes de communication inter-processus (IPC en anglais) :
#include <signal.h> int kill(pid_t pid, int sig); int raise(int sig); int sigaction(int sig, const struct sigaction *act, struct sigaction *oact);void sigint_handler(int sig) { write(0, "Recu SIGINT!\n", 13); } int main(void) { void sigint_handler(int sig); char s[200]; struct sigaction sa; sa.sa_handler = sigint_handler; sa.sa_flags = 0; sigemptyset(&sa.sa_mask); sigaction(SIGINT, &sa, NULL); printf("Entrez du texte: "); printf("message: %s\n", s); }void sigint_handler(int sig) { write(0, "Recu SIGINT!\n", 13); } int main(void) { void sigint_handler(int sig); char s[200]; struct sigaction sa; sa.sa_handler = sigint_handler; sa.sa_flags = SA_RESTART; sigemptyset(&sa.sa_mask); sigaction(SIGINT, &sa, NULL); printf("Entrez du texte: "); printf("message: %s\n", s); }
Entrez du texte: bonjour^CRecu SIGINT! fgets: Interrupted system callEntrez du texte: bonjour^CRecu SIGINT! coucou^CRecu SIGINT! salut message: salut
Un processus peut envoyer un signal à un autre
SIGINT provoque par défaut l'arrêt du processus)SIGKILL, SIGSTOP)Exemples de signaux :
SIGINT (^C)SIGSTOPSIGCONTSIGTERM (kill)SIGKILL (kill -9)SIGQUIT (fermeture du terminal)SIGCHLD (fils terminé ou stoppé)SIGUSR1SIGUSR2 (pas de comportement par défaut)struct sigaction est un type contenant plusieurs champs, parmi lesquels :
sa_handler : la fonction handler (ou SIG_IGN pour ignorer)sa_mask : liste de signaux à ignorer pendant le traîtementsa_flags : des options#include <unistd.h>
int pipe(int fildes[2]);
int main(void) {
int pfds[2];
char buf[30];
if (pipe(pfds) == -1) {
perror("pipe");
exit(1);
}
printf("ecriture (%d)\n", pfds[1]);
write(pfds[1], "test", 5);
printf("lecture (%d)\n", pfds[0]);
read(pfds[0], buf, 5);
printf("recu: %s\n", buf);
}
int main(void) {
int pfds[2];
char buf[30];
pipe(pfds);
if (!fork()) {
printf("(FILS) ecriture\n");
write(pfds[1], "test", 5);
printf("(FILS) fin\n");
exit(0);
} else {
printf("(PERE) lecture\n");
read(pfds[0], buf, 5);
printf("(PERE) lu: %s\n", buf);
wait(NULL);
}
}
(PERE) lecture
(FILS) ecriture
(FILS) fin
(PERE) lu: test
$ ls | wc -l
int main(void) {
int pfds[2];
pipe(pfds);
if (!fork()) {
close(1); // fermer stdout
dup(pfds[1]); //stdout = pfds[1]
execlp("ls", "ls", NULL);
} else {
close(0); // fermer stdin
dup(pfds[0]); // stdin = pfds[0]
execlp("wc", "wc", "-l", NULL);
}
}
Structure abstraite dans laquelle on peut lire et écrire des données
pipe créé deux descripteurs de fichiers (deux bouts)cat a.txt|head -n 10)forkint main(void) { char s[300]; int num, fd; mknod("my_fifo", S_IFIFO | 0666, 0); printf("attente...\n"); fd = open("my_fifo", O_WRONLY); printf("connecté !\n"); while (gets(s), !feof(stdin)) { write(fd, s, strlen(s)); } }int main(void) { char s[300]; int num, fd; mknod("my_fifo", S_IFIFO | 0666, 0); printf("attente...\n"); fd = open("my_fifo", O_RDONLY); printf("connecté !\n"); do { num = read(fd, s, 300); s[num] = '\0'; printf("lu: %s\n", s); } while (num > 0); }
File (first in, first out)
open, read, write, etc.)open() bloque jusqu'à ce que les deux extrêmités soient ouvertesstruct flock fl;
int fd;
fl.l_type = F_WRLCK; // autres types: F_RDLCK, F_UNLCK
fl.l_whence = SEEK_SET; // autres: SEEK_CUR, SEEK_END
fl.l_start = 0;
fl.l_len = 0; // tout le fichier
fl.l_pid = getpid();
fd = open("filename", O_WRONLY);
fcntl(fd, F_SETLKW, &fl);
On peut verrouiller une portion de fichier
On peut obtenir la même chose avec des sémaphores
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);
int semctl(int semid, int semnum, int cmd, ...);
int semop(int semid, struct sembuf *sops, unsigned int nsops);
Semblable aux verrous, mais plus versatiles
Attention : les sémaphores systèmes ne sont pas les mêmes que les sémaphores POSIX (vus en TD)
Un sémaphore a une valeur (entier relatif)
int shmget(key_t key, size_t size, int shmflg); void *shmat(int shmid, void *shmaddr, int shmflg); int shmdt(void *shmaddr); int shmctl(int shmid, int cmd, struct shmid_ds *buf);key_t key; int shmid; char *data; key = ftok("/home/toto/fichier", 'R'); shmid = shmget(key, 1024, 0644 | IPC_CREAT); data = shmat(shmid, (void *)0, 0); if (data == (char *)(-1)) { perror("shmat"); } gets(data); printf("partagé: %s\n", data); shmctl(shmid, IPC_RMID, NULL);
Bloc de mémoire commun à deux processus
shmdtshmctlvoid *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off);
int munmap(caddr_t addr, size_t len);
int fd, pagesize;
char *data;
fd = open("toto", O_RDONLY);
pagesize = getpagesize();
data = mmap((caddr_t)0, pagesize,
PROT_READ, MAP_SHARED, fd, pagesize);
Si on veut partager un fichier entre deux processus, il est parfois plus simple de mettre le fichier dans la mémoire et de manipuler des adresses
openmmapArguments de mmap
addr : adresse où mettre le fichier (en général on laisse l'OS choisir)len : taille du bloc à mettre en mémoireprot : permissions du bloc (doit être compatible avec les paramètre de open)flags : optionsfiledes : descripteur obtenu par openoff : position du début du bloc à mettre en mémoire#include <sys/socket.h>
int socket(int domain, int type, int protocol);
int bind(int socket, const struct sockaddr *address, socklen_t address_len);
ssize_t recv(int socket, void *buffer, size_t length, int flags);
ssize_t send(int socket, const void *buffer, size_t length, int flags);
Tubes bi-directionnels à travers un réseau