Differences

This shows you the differences between two versions of the page.

Link to this comparison view

sde2:laboratoare:05_rust [2023/04/03 14:02]
cristiana.andrei created
sde2:laboratoare:05_rust [2023/04/04 06:21] (current)
cristiana.andrei [Objectifs]
Line 1: Line 1:
 ====== TP 05 - Communication Entre Processus ====== ====== TP 05 - Communication Entre Processus ======
 +
 +<note warning>
 +Vous devez **accepter** le assignment d'ici et travailler avec ce repository: [[https://​classroom.github.com/​a/​lhtkAUIt|Lab5]]
 +</​note>​
 +
  
 ===== Objectifs ===== ===== Objectifs =====
 Le but de ce TP est d'​apprendre à utiliser ​ Le but de ce TP est d'​apprendre à utiliser ​
   * La pipe   * La pipe
-  * Utiliser les signaux 
- 
  
 ===== Pipe ===== ===== Pipe =====
 Une **pipe** est une forme de //​redirection//​ (transfert de la sortie standard vers une autre destination) qui est utilisée dans Linux et d'​autres systèmes d'​exploitation de type Unix pour envoyer la sortie d'une commande/​programme/​processus à une autre commande/​programme/​processus pour un traitement ultérieur . Une **pipe** est une forme de //​redirection//​ (transfert de la sortie standard vers une autre destination) qui est utilisée dans Linux et d'​autres systèmes d'​exploitation de type Unix pour envoyer la sortie d'une commande/​programme/​processus à une autre commande/​programme/​processus pour un traitement ultérieur .
 +
 +Le canal est un mécanisme de communication à sens unique entre deux processus. Dans la plupart des implémentations UNIX, un canal apparaît comme une zone mémoire d'une certaine taille dans l'​espace du noyau. Les processus qui communiquent via un canal anonyme doivent avoir un certain degré de parenté; généralement,​ un processus qui crée un pipe sera alors appelé une fork, et le pipe sera utilisé pour la communication parent-enfant. Dans tous les cas, les processus qui communiquent via des canaux anonymes ne peuvent pas être créés par différents utilisateurs du système.
  
 Pipe est utilisé pour combiner deux commandes ou plus, et dans ce cas, la sortie d'une commande agit comme entrée d'une autre commande, et la sortie de cette commande peut servir d'​entrée pour la commande suivante et ainsi de suite. Il peut également être visualisé comme une connexion temporaire entre deux ou plusieurs commandes/​programmes/​processus. Pipe est utilisé pour combiner deux commandes ou plus, et dans ce cas, la sortie d'une commande agit comme entrée d'une autre commande, et la sortie de cette commande peut servir d'​entrée pour la commande suivante et ainsi de suite. Il peut également être visualisé comme une connexion temporaire entre deux ou plusieurs commandes/​programmes/​processus.
Line 16: Line 21:
 </​note>​ </​note>​
  
-===== Signaux en Rust ===== +<code c>
-Les processus tels que les applications en ligne de commande doivent **réagir** aux signaux envoyés par le système d'​exploitation. L'​exemple le plus courant est probablement Ctrl + C, le signal qui indique généralement à un processus de se terminer. Pour gérer les signaux dans les programmes Rust, vous devez considérer comment vous pouvez recevoir ces signaux ainsi que comment vous pouvez y réagir.+
  
-<​note>​ +use nix::​unistd::​pipe;​
-Un signal est une interruption logicielle dans le flux d'​exécution de processus normal. +
-</​note>​+
  
-L'​ensemble des types de signaux est fini; le système d'​exploitation conserve, pour chaque processus, un tableau d'​actions choisi par lui, pour chaque type de signal. À tout moment, ces actions sont bien déterminées. Au début du processus, la table d'​actions est initialisée avec les valeurs par défaut. Le mode de traitement du signal n'est pas décidé lors de la réception du signal par le processus, mais il est automatiquement choisi dans le tableau. Les signaux sont synchrones / asynchrones avec le flux d'​exécution de processus qui reçoit le signal si l'​événement qui provoque l'​envoi du signal est synchrone / asynchrone avec le flux d'​exécution de processus.+fn main() {
  
-=== Emission et réception de signaux === +    let (fdw0, fdw1) pipe().unwrap();
-Lorsqu'​un signal est généré, il passe dans un état en attenteNormalement,​ il reste dans cet état pendant très peu de temps et est ensuite envoyé au processus de destination. Cependant, si ce type de signal est actuellement verrouillé,​ il pourrait rester indéfiniment en état de veille jusqu'​à ce que les signaux de ce type soient déverrouillés. Une fois ce type de signal déverrouillé,​ il sera envoyé immédiatement. +
-Lorsque le signal a été reçu, immédiatement ou tard, l'​action spécifiée pour ce signal est exécutée. Pour certains signaux, tels que ''​ SIGKILL ''​ et ''​ SIGSTOP '',​ l'​action est ** fixe ** (le processus est terminé), mais, pour la plupart des signaux, le programme peut choisir de: +
-  * **ignore** le signal +
-  * spécifier une fonction de type **handler** +
-  * accepte ** l'​action par défaut ** pour ce type de signal.+
  
-=== Types de signaux standard === +}
-Cette section présente les noms des différents types de signaux standard et décrit le type d'​événements qu'ils indiquent. +
-<​note>​ Chaque nom de signal est une ** définition de macro ** qui représente,​ en fait, un entier positif (le numéro de ce type de signal).</​note>​ +
-Un programme ne doit jamais faire d'​hypothèses sur le code numérique d'un type particulier de signal, mais plutôt s'y référer toujours par son nom. En effet, un nombre pour un type de signal peut ** varier ** d'un système à l'​autre,​ mais leurs noms sont standard. Pour la liste complète des signaux pris en charge par un système, vous pouvez exécuter sur la ligne de commande: +
-<code bash> +
-$ kill -l +
-  +
-     1) SIGHUP ​      2) SIGINT ​      3) SIGQUIT ​     4) SIGILL +
-     5) SIGTRAP ​     6) SIGABRT ​     7) SIGBUS ​      8) SIGFPE +
-     9) SIGKILL ​    10) SIGUSR1 ​    11) SIGSEGV ​    12) SIGUSR2 +
-    13) SIGPIPE ​    14) SIGALRM ​    15) SIGTERM ​    17) SIGCHLD +
-    18) SIGCONT ​    19) SIGSTOP ​    20) SIGTSTP ​    21) SIGTTIN +
-    22) SIGTTOU ​    23) SIGURG ​     24) SIGXCPU ​    25) SIGXFSZ +
-    26) SIGVTALRM ​  27) SIGPROF ​    28) SIGWINCH ​   29) SIGIO +
-    30) SIGPWR ​     31) SIGSYS ​     33) SIGRTMIN ​   34) SIGRTMIN+1 +
-    35) SIGRTMIN+2 ​ 36) SIGRTMIN+3 ​ 37) SIGRTMIN+4 ​ 38) SIGRTMIN+5 +
-    39) SIGRTMIN+6 ​ 40) SIGRTMIN+7 ​ 41) SIGRTMIN+8 ​ 42) SIGRTMIN+9 +
-    43) SIGRTMIN+10 44) SIGRTMIN+11 45) SIGRTMIN+12 46) SIGRTMIN+13 +
-    47) SIGRTMIN+14 48) SIGRTMIN+15 49) SIGRTMAX-15 50) SIGRTMAX-14 +
-    51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10 +
-    55) SIGRTMAX-9 ​ 56) SIGRTMAX-8 ​ 57) SIGRTMAX-7 ​ 58) SIGRTMAX-6 +
-    59) SIGRTMAX-5 ​ 60) SIGRTMAX-4 ​ 61) SIGRTMAX-3 ​ 62) SIGRTMAX-2 +
-    63) SIGRTMAX-1 ​ 64) SIGRTMAX+
 </​code>​ </​code>​
-Les noms de signaux sont définis dans l'​en-tête ''​ signal.h ''​ sous Unix. En général, les signaux ont des rôles prédéfinis,​ mais ils peuvent être remplacés par le programmeur. 
-Les plus connus sont les signaux suivants: 
-  * ''​SIGINT''​ - transmis lorsque la combinaison est enfoncée ''​CTRL+C'';​ 
-  * ''​SIGQUIT ''​- transmis lorsque la combinaison est enfoncée ''​CTRL+\'';​ 
-  * ''​SIGSEGV''​ - transmis lors de l'​accès à un emplacement de mémoire invalide, etc. 
-  * ''​SIGKILL''​ - ** ne peut pas ** être ignoré ou remplacé. La transmission de ce signal a pour effet de mettre fin au processus, quel que soit le contexte. 
  
-<note important>​ +Le tuple ''​ (fdw0, fdw1) ''​ contient après l'​exécution de la fonction 2 descripteurs de fichiers: 
-Pour gerer les signaux en Rust on utilise [[https://​docs.rs/​nix/​latest/​nix/​sys/​signal/​fn.signal.html|nix::​sys::​signal::​signal]]. +   * ''​ fdw0 '',​ ouvert à la lecture; 
-</​note>​+   * ''​ fdw1 '',​ ouvert pour l'​écriture;​ 
 +La sortie de ''​ fdw1 ''​ est considérée comme une entrée pour ''​ fdw0 ''​.. 
  
-===== Tuer des processus ===== +** Remarques**:​ 
-Si un processus Linux ne répond ​plus ou consomme trop de ressources, vous devrez peut-être le tuer. +  * la lecture / écriture depuis / vers les canaux est atomique si vous ne lisez / écrivez pas plus de '' ​PIPE_BUF ​'' ​((limite globale fixée par défaut sur Linux à 4096 octets)) octets
- +  ​* ​la lecture / écriture depuis / vers les pipes se fait à l'aide des fonctions ​'' ​stdin().read_line() ''​ / ''​ stdout().write () ''​. ​
-La plupart des processus ont leurs propres méthodes d'arrêt. Malheureusement,​ les processus peuvent mal fonctionner et ne pas se laisser arrêter. Si un processus d'arrière-plan en cours d'exécution ne répond pas, il devient nécessaire d'utiliser une commande pour le tuer+
- +
-En Rust, on utilise ​la fonction ​''​kill'' qui force le processus fils à se fermer. Si l'​enfant est déjà sorti, une erreur InvalidInput est renvoyée. Cela équivaut à envoyer un **SIGKILL** sur les plates-formes Unix. +
- +
-Exemple: +
-<code c> +
-use std::​process::​Command;​ +
- +
-let mut command = Command::​new("​yes"​);​ +
-if let Ok(mut child= command.spawn() +
-    child.kill().expect("​command wasn't running"​)+
-} else { +
-    println!("​yes command didn't start"​);​ +
-+
-</​code>​+
  
 +La plupart des applications qui utilisent des pipes ferment dans chacun des processus l'​extrémité du pipe ** inutilisé ** en communication unidirectionnelle. Si l'un des descripteurs est fermé, les règles s'​appliquent:​
 +  * une lecture à partir d'un canal pour lequel le ** descripteur d'​écriture ** a été fermé, après que toutes les données ont été lues, renverra ''​ 0 '',​ indiquant la fin du fichier. Le descripteur d'​écriture peut être dupliqué afin que plusieurs processus puissent écrire dans le canal. Habituellement,​ dans le cas des canaux anonymes, il n'y a que deux processus, l'un qui écrit et l'​autre qui lit, tandis que dans le cas des fichiers de canal nommé (FIFO), il peut y avoir plusieurs processus qui écrivent des données.
 +  * une écriture dans un tube pour lequel le descripteur ** read ** a été fermé provoque la génération du signal ''​ SIGPIPE ''​. Si le signal est capturé et revient de la routine de traitement, la fonction système ''​ écriture ''​ renvoie une erreur et la variable ''​ errno ''​ a la valeur ''​ EPIPE ''​.
 +<note important>​ L'​erreur ** la plus courante **, lorsque vous travaillez avec des pipes, vient de la négligence du fait que ''​EOF''​ n'est pas envoyé à travers les pipes (la lecture des pipes ne se termine pas) à moins que toutes les ** extrémités ne soient fermées**. ** TOUS ** les processus qui ont ouvert le descripteur de pipe (dans le cas d'une fork, assurez-vous de fermer les extrémités du pipe dans le processus parent).</​note>​
 ===== Sugestions ===== ===== Sugestions =====
  
Line 107: Line 66:
 ===== Bibliographie ===== ===== Bibliographie =====
   * pipe [[https://​docs.rs/​nix/​latest/​nix/​unistd/​fn.pipe.html]]   * pipe [[https://​docs.rs/​nix/​latest/​nix/​unistd/​fn.pipe.html]]
-  * kill [[https://​docs.rs/​nix/​latest/​nix/​sys/​signal/​fn.kill.html]] 
-  * signal [[https://​docs.rs/​nix/​latest/​nix/​sys/​signal/​fn.signal.html]] 
  
 ===== Sujets ===== ===== Sujets =====
-  - Écrivez un programme qui crée un tuyau et des bifurcations. Du parent, lisez à partir du clavier un message et envoyez-le par le canal à l'​enfant.+  - Écrivez un programme qui crée un pipe et un processus (processus enfant en utlisant [[https://​docs.rs/​nix/​0.26.2/​nix/​unistd/​fn.fork.html|fork]]). Du parent, lisez à partir du clavier un message et envoyez-le par le canal à l'​enfant.
     - Inversez le message dans l'​enfant et envoyez-le au parent.     - Inversez le message dans l'​enfant et envoyez-le au parent.
-  - Clonez le repository ​[[https://github.com/UPB-FILS-SdE2/Solutions/tree/main|Solutions]] et compilez ex2Exécutez-le et utilisez la commande shell kill pour lui envoyer des signaux. +  - Écrivez un programme qui crée un pipe et un processus (un processus enfant en utlisant ​[[https://docs.rs/nix/0.26.1/nix/unistd/​fn.fork.html|fork]])Le processus enfant redirige son ecran vers le pipe et exécute ls -l. Le processus parent lit la sortie ​de l'​enfant ​à partir ​du pipe et l'affiche
-    ​Modifiez-le pour qu'à chaque fois qu'il reçoit un signal, il imprime une lettre différente : a - SIGHUP, b - SIGINT, n - SIQUIT, s - SIGTRAP, espace - SIGFPE. Écrivez un autre programme en Rust qui lui envoie des signaux pour qu'il imprime ''​bannanas bannanas''​. Le deuxième programme reçoit le pid de destination ​à partir ​d'un argument de ligne de commande+  - Écrivez ​un programme qui crée un pipe et 2 processus ​(deux processus ​enfant ​en utlisant ​[[https://docs.rs/nix/0.26.1/nix/unistd/fn.fork.html|fork]] doix fois). Le premier enfant exécute ls -l et le deuxième enfant exécute grep src. Le parent connecte l'​affichage du premier enfant au clavier du deuxième enfant avec un pipe. 
-  - Créez ​un programme qui fait fork et entre dans une boucle infinie ​(avec un sleep). Son enfant ​attend quelques secondes puis sort. Écrivez un message à l'​écran lorsque l'​enfant sort. Utilisez SIGCHLD. +  
- +
-===== Solutions ===== +
-[[https://github.com/UPB-FILS-SdE2/Solutions/tree/main/tp5|Solutions]] +
sde2/laboratoare/05_rust.1680519750.txt.gz · Last modified: 2023/04/03 14:02 by cristiana.andrei
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0