informatica:sol:laboratorio15:esercitazionia:scexamples
Indice
Alcuni esempi di semplici programmi C con processi e pipe
nproc.c (chiamate: fork, wait, getpid)
Si creano nproc processi figli che eseguono un certo numero di iterazioni, si attende quindi la loro terminazione stampando la condizione di terminazione l'exit status e l'eventuale segnale che ha terminato il processo.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <errno.h>
// utility macro
#define SYSCALL(r,c,e) \
if((r=c)==-1) { perror(e);exit(errno); }
// numero di processi di default
const int NPROC = 2;
// forward declaration, procedura eseguita da un processo
void procF(int);
int main(int argc, char * argv[]) {
int nproc;
// check arguments
if(argc>1) nproc = atoi(argv[1]);
else nproc = NPROC;
// per distinguere tra il processo padre ed i processi figli
int ppid = getpid();
// genero nproc processi figli
for(int i=0;i<nproc;i++) {
int r;
SYSCALL(r,fork(),"creando un processo");
if(r == 0) { // processo figlio
procF(i+2); // eseguo i+2 iterazioni
break; // altrimenti genero troppi processi
} else { // processo padre
printf("Creato processo figlio con pid %d\n",r);
// continua il ciclo
}
}
// il solo processo padre attende i figlio
if(getpid() == ppid) {
int status,r;
for(int i=0;i<nproc;i++) {
SYSCALL(r, wait(&status), "wait");
if(WIFEXITED(status))
printf("Figlio con pid %d terminato con exit, codice %d\n",
r, WEXITSTATUS(status));
else if (WIFSIGNALED(status)) {
printf("Figlio con pid %d terminato da un segnale (sig=%d)\n",
r, WTERMSIG(status));
} else if (WIFSTOPPED(status) || WIFCONTINUED(status))
printf("Figlio con pid %d interrotto da o ripartito con un segnale\n",r);
}
} // else sono un processo figlio e termino senza fare nient'altro
return getpid() % 256; // termino con questo codice
}
// procedura eseguita dai processi figli
void procF(int niter) {
for(int i=0;i<niter;++i) {
printf("Sono il processo %d all'iterazione %d\n",getpid(),i);
sleep(1);
}
}
command.c (chiamate: fork, wait, getpid, execvp)
Programma che prende come argomento un programma eseguibile ed i suoi eventuali argomenti e lancia il programma attendendone la terminazione.
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
// utility macro
#define SYSCALL(r,c,e) \
if((r=c)==-1) { perror(e);exit(errno); }
int main(int argc, char *argv[]) {
if (argc == 1) {
fprintf(stderr, "usa: %s comando [argomenti-comando]\n", argv[0]);
return EXIT_FAILURE;
}
int pid;
SYSCALL(pid, fork(), "fork");
if(pid == 0) { // figlio
int r;
execvp(argv[1],&argv[1]);
perror("execvp");
return errno;
}
int status;
SYSCALL(pid, wait(&status),"wait");
printf("Processo %d terminato con ",pid);
if(WIFEXITED(status)) printf("exit(%d)\n",WEXITSTATUS(status));
else printf("un segnale (sig=%d)\n", WTERMSIG(status));
return 0;
}
zombie.c (chiamate: fork, waitpid, getpid, execlp)
Il seguente programma crea un numero di processi zombie mostrando il loro stato con il comando unix 'ps'.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/wait.h>
// utility macro
#define SYSCALL(r,c,e) \
if((r=c)==-1) { perror(e);exit(errno); }
int main(int argc, char * argv[]) {
const int SEC=2;
if (argc != 2) {
fprintf(stderr, "usa: %s num-proc\n", argv[0]);
return EXIT_FAILURE;
}
int nproc = atoi(argv[1]);
int pid;
for(int i=0;i<nproc;++i) {
SYSCALL(pid,fork(),"fork");
if(pid==0) { // figlio
sleep(SEC);
exit(0); // esco con successo
} else
printf("%d: creato processo con pid = %d\n", getpid(), pid);
}
// solo il processo padre arriva qui
// aspettiamo un po' in modo da essere "sicuri"
// che i processi figli siano terminati
sleep(2*SEC);
printf("Stato dei processi prima delle wait:\n");
SYSCALL(pid,fork(),"fork");
if(pid==0) {
execlp("ps","ps",NULL);
perror("eseguendo ps");
exit(errno);
} else {
int stato;
printf("Lanciato il processo con pid = %d per eseguire un ps\n",pid);
SYSCALL(pid,waitpid(pid,&stato,0),"waitpid");
printf("Processo %d terminato\n",pid);
}
// adesso attendiamo la terminazione dei processi
for(int i=0;i<nproc;++i) {
int stato;
SYSCALL(pid,wait(&stato),"wait");
if(WIFEXITED(stato))
printf("Processo con pid %d terminato con una exit(%d)\n",
pid,WEXITSTATUS(stato));
}
printf("Stato dei processi dopo la terminazione:\n");
SYSCALL(pid,fork(),"creando il processo ps");
if(pid==0) {
execlp("ps","ps",NULL);
perror("eseguendo il ps");
exit(0);
} else {
int stato;
SYSCALL(pid,waitpid(pid,&stato,0),
"attendendo la terminazione del processo ps");
}
return 0;
}
pipe2proc.c (chiamate: fork, wait, getpid, write, pipe, dup, execve)
Il programma crea un processo figlio che esegue il comando sort sull'input ricevuto in una pipe che connette lo standard output del padre con lo standard input del figlio ( padre – pipe –> figlio).
Il programma produce in output l'equivalente prodotto dal comando shell:
echo "Ciao mondo ! Passo e chiudo ..." | tr ' ' '\n' | LC_ALL=C sort
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <errno.h>
// utility macro
#define SYSCALL(r,c,e) \
if((r=c)==-1) { perror(e);exit(errno); }
int main(int argc, char *argv[]) {
int canale[2];
int r;
SYSCALL(r, pipe(canale), "pipe");
if (fork() != 0) { // padre
close(1);
SYSCALL(r,dup(canale[1]),"dup");
// chiudo tutti i descrittori che non uso
close(canale[1]);
close(canale[0]);
} else { // figlio
close(0);
SYSCALL(r, dup(canale[0]), "dup");
// chiudo tutti i descrittori che non uso prima di chiamare la exec
close(canale[1]);
close(canale[0]);
// utilizzo la chiamata di sistema execve specificando le
// variabili di ambente del processo sort
char *path = getenv("PATH");
char envpath[strlen("PATH=")+strlen(path)+1];
char envlcall[] = "LC_ALL=C";
snprintf(envpath, sizeof(envpath), "PATH=%s",path);
char *envp[] = { envpath, envlcall, NULL};
char *cmd[] = { "/usr/bin/sort", NULL };
execve(cmd[0], cmd, envp);
perror("execve");
exit(errno);
}
SYSCALL(r, write(1, "mondo\n", 7), "write1");
SYSCALL(r, write(1, "Ciao\n", 6), "write2");
SYSCALL(r, write(1, "!\n", 3), "write3");
SYSCALL(r, write(1, "Passo\n", 7), "write3");
SYSCALL(r, write(1, "e\n", 3), "write3");
SYSCALL(r, write(1, "chiudo\n", 8), "write3");
SYSCALL(r, write(1, "...", 4), "write3");
// chiudo l'output prima di attendere la terminazione
close(1);
// attendo la terminazione del processo figlio
int status;
SYSCALL(r, wait(&status), "wait");
return 0;
}
informatica/sol/laboratorio15/esercitazionia/scexamples.txt · Ultima modifica: 26/04/2015 alle 13:34 (11 anni fa) da Massimo Torquati
