Différences entre versions de « C pipe »

De The Linux Craftsman
Aller à la navigation Aller à la recherche
Ligne 114 : Ligne 114 :
 
close(tube[0]);
 
close(tube[0]);
 
close(tube[1]);
 
close(tube[1]);
 +
}
 +
}
 +
waitForAll();
 +
return EXIT_SUCCESS;
 +
}
 +
</source>
 +
= Utilisation bidirectionnel =
 +
Dans cette exemple, on créer une structure qui va contenir les deux tubes pour plus de facilité:
 +
<source lang="c">
 +
#include <stdio.h>
 +
#include <stdlib.h>
 +
#include <unistd.h>
 +
#include <sys/types.h>
 +
#include <sys/wait.h>
 +
#include <string.h>
 +
 +
// Structure avec des tubes full-duplex
 +
typedef struct fdpipe {
 +
int father[2];
 +
int son[2];
 +
} fdpipe;
 +
 +
// Nombre total de thread
 +
#define NB_FORK 10
 +
// Taille du message
 +
#define LENGTH_MSG 50
 +
// Tableau contenant le message
 +
char message[LENGTH_MSG] = "";
 +
 +
// Fonction exécutée dans le fork
 +
void job(fdpipe * pipes) {
 +
int tid = getpid();
 +
// timer pour attendre maximum 5 secondes
 +
int i = 5;
 +
while (i > 0) {
 +
// lecture dans le tube
 +
if (read((*pipes).father[0], message, LENGTH_MSG) > 0) {
 +
printf("Message du processus [%i] : %s\n", tid, message);
 +
// Ecriture du message dans le tableau
 +
sprintf(message, "je suis [%i] et j'ai bien reçu ton message !\n", tid);
 +
write((*pipes).son[1], message, LENGTH_MSG);
 +
break;
 +
}
 +
sleep(1);
 +
}
 +
}
 +
// Fonction qui attend chacun des processus fils
 +
void waitForAll() {
 +
int status;
 +
pid_t pid;
 +
int n = 0;
 +
while (n < NB_FORK) {
 +
pid = wait(&status);
 +
n++;
 +
}
 +
}
 +
 +
int main() {
 +
for (int i = 0; i < NB_FORK; i++) {
 +
fdpipe pipes;
 +
pipe(pipes.father);
 +
pipe(pipes.son);
 +
pid_t pid = fork();
 +
if (pid == -1) {
 +
// Il y a une erreur
 +
perror("fork");
 +
return EXIT_FAILURE;
 +
} else if (pid == 0) {
 +
// On est dans le fils
 +
close(pipes.father[1]);
 +
job(&pipes);
 +
close(pipes.father[0]);
 +
close(pipes.son[0]);
 +
close(pipes.son[1]);
 +
exit(EXIT_SUCCESS);
 +
} else {
 +
// On est dans le père
 +
// Ecriture du message dans le tableau
 +
sprintf(message, "Fork [%i], je suis ton père !\n", pid);
 +
// Ecriture du message dans le tube
 +
write(pipes.father[1], message, LENGTH_MSG);
 +
while (i > 0) {
 +
// lecture dans le tube
 +
if (read(pipes.son[0], message, LENGTH_MSG) > 0) {
 +
printf("Réponse du fils : %s\n", message);
 +
break;
 +
}
 +
sleep(1);
 +
}
 +
close(pipes.father[1]);
 +
close(pipes.father[0]);
 +
close(pipes.son[0]);
 +
close(pipes.son[1]);
 
}
 
}
 
}
 
}

Version du 19 octobre 2018 à 19:45

Introduction

Un tube est un canal par lequel les informations circulent de manière uni-directionnel. Un processus écrit dans l'entrée du tube et un autre processus lit les informations en sortie.

Manipulation des tubes

Création

La première étape est la création d'un tube:

#include <unistd.h>

int tube[2];

int pipe(int tube[2]);
  • tube[0] → contiendra le fichier descripteur de l'extrémité de lecture
  • tube[1] → contiendra le fichier descripteur de l'extrémité d'écriture
  • Le retour sera :
    • '0' si tout s'est bien passé
    • '1' si une erreur survient et errno est positionné

Écriture

Pour écrire dans un tube :

#include <unistd.h>

ssize_t write(int tube[0], const void *message, size_t longueur);
  • tube[0] → le fichier descripteur de l'extrémité d'écriture
  • message → le message à écrire
  • longueur → la longueur du message
  • ssize_t → le nombre d'octets écrits

Lecture

Pour lire dans un tube :

#include <unistd.h>

ssize_t read(int tube[1], void *message, size_t longueur);
  • tube[1] → le fichier descripteur de l'extrémité de lecture
  • message → un tableau de caractère qui contiendra le message à lire
  • longueur → la longueur du message à lire
  • ssize_t → le nombre d'octets lus

fermeture

Un fois la lecture terminé on ferme le tube:

int close(int descripteur);
  • descripteur : une extrémité du tube

Utilisation uni-directionnel

Ci-dessous un exemple qui permet au père de communiquer avec ces fils:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>

// Nombre total de thread
#define NB_FORK 2
// Taille du message
#define LENGTH_MSG 30
// Tableau contenant le message
char message[LENGTH_MSG] = "";

// Fonction exécutée dans le fork
void job(int * tube) {
	int tid = getpid();
	// timer pour attendre maximum 5 secondes
	int i = 5;
	while (i > 0) {
		// lecture dans le tube
		if (read(*tube, message, LENGTH_MSG) > 0) {
			printf("Message du processus [%i] : %s", tid, message);
			break;
		}
		sleep(1);
	}
}
// Fonction qui attend chacun des processus fils
void waitForAll() {
	int status;
	pid_t pid;
	int n = 0;
	while (n < NB_FORK) {
		pid = wait(&status);
		n++;
	}
}

int main() {
	for (int i = 0; i < NB_FORK; i++) {
		int tube[2];
		pipe(tube);
		pid_t pid = fork();
		if (pid == -1) {
			// Il y a une erreur
			perror("fork");
			return EXIT_FAILURE;
		} else if (pid == 0) {
			// On est dans le fils
			close(tube[1]);
			job(&tube[0]);
			close(tube[0]);
			exit(EXIT_SUCCESS);
		} else {
			// On est dans le père
			// Ecriture du message dans le tableau
			sprintf(message, "Fork [%i], je suis ton père !\n", pid);
			// Ecriture du message dans le tube
			write(tube[1], message, LENGTH_MSG);
			close(tube[0]);
			close(tube[1]);
		}
	}
	waitForAll();
	return EXIT_SUCCESS;
}

Utilisation bidirectionnel

Dans cette exemple, on créer une structure qui va contenir les deux tubes pour plus de facilité:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>

// Structure avec des tubes full-duplex
typedef struct fdpipe {
	int father[2];
	int son[2];
} fdpipe;

// Nombre total de thread
#define NB_FORK 10
// Taille du message
#define LENGTH_MSG 50
// Tableau contenant le message
char message[LENGTH_MSG] = "";

// Fonction exécutée dans le fork
void job(fdpipe * pipes) {
	int tid = getpid();
	// timer pour attendre maximum 5 secondes
	int i = 5;
	while (i > 0) {
		// lecture dans le tube
		if (read((*pipes).father[0], message, LENGTH_MSG) > 0) {
			printf("Message du processus [%i] : %s\n", tid, message);
			// Ecriture du message dans le tableau
			sprintf(message, "je suis [%i] et j'ai bien reçu ton message !\n", tid);
			write((*pipes).son[1], message, LENGTH_MSG);
			break;
		}
		sleep(1);
	}
}
// Fonction qui attend chacun des processus fils
void waitForAll() {
	int status;
	pid_t pid;
	int n = 0;
	while (n < NB_FORK) {
		pid = wait(&status);
		n++;
	}
}

int main() {
	for (int i = 0; i < NB_FORK; i++) {
		fdpipe pipes;
		pipe(pipes.father);
		pipe(pipes.son);
		pid_t pid = fork();
		if (pid == -1) {
			// Il y a une erreur
			perror("fork");
			return EXIT_FAILURE;
		} else if (pid == 0) {
			// On est dans le fils
			close(pipes.father[1]);
			job(&pipes);
			close(pipes.father[0]);
			close(pipes.son[0]);
			close(pipes.son[1]);
			exit(EXIT_SUCCESS);
		} else {
			// On est dans le père
			// Ecriture du message dans le tableau
			sprintf(message, "Fork [%i], je suis ton père !\n", pid);
			// Ecriture du message dans le tube
			write(pipes.father[1], message, LENGTH_MSG);
			while (i > 0) {
				// lecture dans le tube
				if (read(pipes.son[0], message, LENGTH_MSG) > 0) {
					printf("Réponse du fils : %s\n", message);
					break;
				}
				sleep(1);
			}
			close(pipes.father[1]);
			close(pipes.father[0]);
			close(pipes.son[0]);
			close(pipes.son[1]);
		}
	}
	waitForAll();
	return EXIT_SUCCESS;
}