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
senza nome 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; }