Lab2: Communication entre processus avec des tuyaux et les fils Java

publicité
Systèmes
d’exploitation
CSI3531
Labo 2
Communication entre processus avec des tuyaux
Fils Java
Partie A – La communication entre processus avec tuyaux
Objectif : Explorer le IPC avec les tuyaux UNIX/Linux
Description
On réutilise les fichiers du laboratoire 1.
Étape 1 : Démarrez la machine virtuel Linux sitedev et faîtes un login au système.
Copiez le fichier « lab2afr.tar » fourni dans votre répertoire de travail (working
directory). Comme dans le labo 1, faites l’extraction des fichiers de cette archive avec tar
–xvf lab2afr.tar. Vous retrouverez les mêmes fichiers que dans le labo 1 et un nouveau
fichier filtre. Ceci est un fichier exécutable qui est exécuté sans paramètres, qui lit de son
entrée standard, et qui est conçu pour lire la sortie de procmon du laboratoire 1 pour
ensuite écrire seulement les lignes lorsque l’état du processus examiné change.
Étape 2 : Complétez le programme mon2.c (un gabarit vous êtes fourni) en suivant les
lignes directrices suivantes :
1. Comme mon du labo 1, le programme mon2 reçoit un argument de la ligne de
commande : le nom M du program qu’il doit exécuter.
2. Le programme mon 2 doit exécuter le programme M (le programme M ne prend aucun
argument) et retenir dans PID l’identificateur du processus lancé.
3. Il doit ensuite exécuter procmon avec l’argument PID.
4. Il doit lancer un autre processus pour rouler le programme filtre sans arguments.
5. La sortie standard de procmon doit être envoyé à l’entré standard de filtre en utilisant
un tuyau, i.e. filtre lira de son entré standard ce que procmon écrit à sa sortie standard.
6. Il attend 20 secondes, termine le programme M, attend encore un autre 2 secondes, et
ensuite essaie de terminer procmon et filtre.
7. Un gabarit pour mon2.c vous êtes fourni pour vous aider à développer le programme.
Notez qu’une bonne partie du code de mon.c peut être copié à mon2.c.
Étape 3 : Compilez votre programme C avec la commande « cc mon2.c –o mon2 ».
Cette commande fait rouler le compilateur C (commande cc) pour compiler le code
source mon2.c pour produire le fichier exécutable mon2. Si la compilation complète avec
succès, le fichier exécutable mon2 se retrouvera dans le répertoire courant.
Étape 4 : Entrez la commande « mon2 calcloop » et observez. Cette commande
lance le programme mon2 que vous avez créé, qui à son tour lance procmon pour
examiner l’exécution de calcloop et filtre pour imprimer seulement les lignes lorsque
l’état de calcloop change.
Étape 5 : Vous pouvez expérimenter avec l’envoie de signaux au processus calcloop.
Après avoir exécuté mon2 calcloop & (& permet de pouvoir exécuter d’autres
commandes) :
Déterminez le pid du calcloop (par exemple avec la commande ps).
Envoyez-y un signal d’arrêt avec la commande « kill –s SIGSTOP pid »
où pid est le pid du calcloop déterminé au dernier point.
Envoyez-y un signal de départ avec la commande « kill –s SIGCONT
pid ».
Notez que vous devez être rapide pour faire le tout à l’intérieur des 20 secondes que roule
calcloop.
Information utile:
L’exécution d’un programme C commence par sa fonction main() qui comprends deux
paramètres, l’entier argc qui donne le nombre d’arguments de la ligne de commande
(qui a fait exécuter le programme) et un tableau de pointeurs à des chaînes de
caractères donnant accès aux arguments de la ligne de commande. Par convention,
argv[0]¸donne le nom du programme et argv[1] donne le premier argument.
L’appel système fork() créée un nouveau processus. Le parent et l’enfant continue au
même point, i.e., le retour de l’appel fork(). Mais chez le parent, fork() retourne le PID
de l’enfant tandis que chez l’enfant, fork() retourne la valeur 0. Pour plus
d’information au sujet de fork(), utilisez man fork.
L’appel système execl(path, arg1, …) remplace l’image dans un processus par un
programme avec des paramètres donnés. Tapez pour connaître la signification exacte
de chacun des paramètres. L’appel execl(“calcloop”,”calcloop”,NULL) remplace le
code dans le processus avec le programme calcloop. L’appel execl(“/bin/ls”, “ls”, “
l”, NULL) exécute le code du programme ls –l.
Vous devez convertir le nombre entier PID à une chaîne de caractère pour l’envoyer
vers procmon. Ceci peut être fait en C avec une fonction de bibliothèque :
sprintf(pidchn,“%d”,pid), où pid est une variable int qui contient la valeur du pid, et
pidchn est un tableau de caractères (char pidchn[20]) qui recevra la chaîne de
caractères du PID à être envoyé vers procmon.
La fonction sleep() qui fera dormir le processus pour le nombre de secondes spécifié
dans son paramètre.
L’appel système kill(pid,sig) qui envoie un signal sig au processus pid.
o Examinez signal.h pour connaître les différents signaux.
o Google est votre ami, le lien suivant suite à une recherche de « signal.h » peut
être utile (il y en a beaucoup plus au sujet des appels et fonctions standards C)
http://www.opengroup.org/onlinepubs/009695399/basedefs/signal.h.html
Un descripteur de fichier (file descriptor) est un nombre entier, qui sert de poignée
(handle) pour identifier un fichier ouvert. Ce descripteur est utilisé avec d’autres
fonctions ou systèmes d’appel tel que read() et write() pour faire des opérations E/S
avec le fichier correspondant.
L’appel pipe(int *dfs) attend un argument qui est un pointeur à un tableau d’entier (i.e.
le nom d’un variable déclaré comme tableau d’int, i.e. int dfs[2], crée un tuyau, et
retourne 2 descripteurs de fichiers dans le tableau reçu : dfs[0] contient la référence au
bout de lecture du tuyau et dfs[1] contient la référence au bout d’écriture du tuyau.
dup2(int oldfd, int newfd) – clone (duplicate) le descripteur oldfd sur le descripteur de
fichier newfd. Si newfd correspond à un fichier ouvert, ce fichier sera d’abords fermé.
Donc le même fichier peut être accéder soit par oldfd, soit par newfd (essentiellement
deux connections au fichier). Voyez http://mkssoftware.com/docs/man3/dup2.3.asp ou
“man dup2” pour plus d’information. Par exemple, le programme suivant :
int main(int argc, char *argv[])
{
int df;
printf(“Bonjour le monde!”)
df = open(“outFile.dat”, “w”);
if (df != -1) dup2(fd, 1);
printf(“Bonjour le monde!”);
close(df);
}
rédigera la sortie standard du programme au fichier “outFile.dat”. Le premier
« Bonjour le monde! » sera imprimer sur la console, tandis que le deuxième sera
stocké dans le fichier « outFile.dat ».
read(int fd, char *buff, int bufSize) – lire du fichier (ou tuyau) identifier par le
descripteur fd un nombre de caractères bufSize et copier les caractères lu dans le
tampon buff. La fonction retourne le nombre de caractères lus (peut être moindre que
bufSize), ou -1 lors d’une erreur, ou 0 lorsque la fin du fichier est atteint (dans le cas
du tuyau, aucun processus est attaché au bout écrivant et aucune donnée existe dans le
tuyau).
write(int fd, char *buff, int buffSize) – Écrit dans le fichier (ou tuyau) fd le nombre de
caractères buffSize retrouver dans le tampon buff.
close(int fd) – ferme un fichier ouvert. Le descripteur fd pourra être réutilisé.
Cette liaison WEB pourrait vous aidez avec la programmation C :
http://www.acm.uiuc.edu/webmonkeys/book/c_guide/
Linux/UNIX offre des pages de documentation (man pages). La commande man « nom
de fonction » imprimera à l’écran de l’information détaillé au sujet de la fonction donnée.
Partie 2 – Les fils Java.
Objectifs :
1. Apprendre comment utiliser les fils – la classe Java Thread.
2. Apprendre comment utiliser les groupements de fils (thread pools) – la classe Java
Executors.
Description
Dans cette partie du labo, vous travaillerez avec une application qui dessine une
représentation de l’ensemble Mandelbrot. L’image sera générée en peinturant un
ensemble de rectangles dans une fenêtre Windows. En utilisant des fils (et groupement de
fils) vous pouvez visuellement voir l’exécution des fils. Pour plus d’information sur cet
ensemble MandelBrot et ses illustrations, consultez le site :
http://www.ddewey.net/mandelbrot/
Étape 1 – Votre première image de l’ensemble Mandelbrot : Faite l’extraction des
fichiers java de l’archive MandelBrot.zip. Compilez le code java avec votre outil favori
de développement java :
MBGlobals.java
- Donne une classe contenant des données globales
MBPaint.java
- Donne une classe pour calculer la couleur des
pixels de l’illustration (elle colore aussi les pixels)
dans un carré donnée de l’image.
MBCanvas.java
- Donne la classe MBCanvas (extension de Canvas),
une composante GUI qui permet de faire des
dessins.
MBFrame.java
- Donne la classe MBFrame (extension de JFrame),
pour créer une fenêtre Windows. Un objet
MBCanvas est ajouté à cette fenêtre.
MandelBrot.java
- On part d’ici. Mandlebrot traduira les arguments
de la commande pour stocker ses valeurs dans
MBGlobals. Ensuite, il créera un objet MBFrame
pour faire apparaître une image de l’ensemble
Mandelbrot selon les arguments de la commande.
Après avoir compilé l’application java, faite l’expérience de créer différentes vues de
l’ensemble Mandelbrot avec la commande suivante:
java MandelBrot <Upper x Coord> <Upper y Coord> <Real Dim> <Pixel Dim> <Fill Dim>
où
<Upper x Coord> et <Upper y Coord>: sont les coordonnées du coin supérieur
à gauche de l’illustration en termes de valeurs réelles. Pour avoir une vue général
de l’ensemble, utilisez les coordonnées -2,2 avec une dimension de 4 (voir Real
Dim).
<Real Dim> - L’application utilise un carré comme toile de fond. Sa valeur
correspond à la dimension réelle du graphe de l’ensemble Mandelbrot. Donc la
valeur 4 donnera une illustration avec les dimensions de 4X4 unités. Avec les
coordonnées -2,2 pour le coin supérieur à gauche, le diagramme aura les
coordonnées suivantes :
• -2, 2 (coin supérieur à gauche)
• 2, 2 (coin supérieur à droite)
• 2, -2 (coin inférieur à droite)
• -2, -2 (coin inférieur à gauche)
<Pixel Dim> - Cette dimension représente la dimension de la toile de fond en
terme de pixels. Elle contrôle la grandeur de la fenêtre produite.
<Fill Dim> - Cette dimension contrôle la grandeur du carré pour remplir les
pixels de l’illustration. Le code fourni, la récursivité est utilisé pour créer
plusieurs objets MBPaint qui remplissent différentes sections de la toile de
l’illustration (objet MBCanvas). L’objectif du lab est de changer le code afin
d’utiliser des fils (threads) pour remplir ces différents carrés.
Essayez les arguments suivants :
java Lab3 -2 2 4 600 50
- Pour un vue générale. Modifiez 600 pour obtenir de différentes
grandeurs de fenêtres.
D’autres vues intéressantes sont possibles avec le suivant:
java Lab3 -2 1 1 600 50
java Lab3 -1 1 1 600 50
java Lab3 -2 0.5 1 600 50
Étape 2 - L’Utilisation des fils: Avec la classe Thread de Java, modifies le code fourni
afin d’utiliser des fils (threads) différents pour remplir chaque carré de remplissage.
Modifier le paramètre <Fill dim> pour voir l’effet du remplissage de l’illustration. Notez
que lorsque vous réduisez la valeur de ce paramètre, le nombre de fils utilisés augmente.
Étape 3 - L’utilisation du groupement de fils (thread pool) : Java offre la classe
« Executors » pour la création de groupements de fils. La méthode statique
« newFixedThreadPool(int nFils) » créer un objet de la classe ExecutorService qui gère
un groupement de nFils fils. Pour créer un tel objet gérant 20 fils, utilisez :
ExecutorService thpool = Executors.newFixedThreadPool(20);
Des tâches peuvent être exécutées avec:
thpool.execute(Runnable task)
Notez que la tâche « task » est un objet qui implémente l’interface Runnable. Consultez
la documentation Java pour les détails de l’utilisation de la classe Executors et l’interface
ExecutorService.
Modifiez le code Java pour utiliser un groupement de fil qui exécutera les tâches définies
par les objets MBCompute. Vous devez voir l’effet de limiter le nombre de fils qui
peuvent exécuter à la fois, surtout en comparant le comportement avec la version l’étape
2). Essayez de varier la grandeur du groupement (nombre de fils) pour voir l’effet de
l’exécution.
Téléchargement