Usa la funzione waitpid in C
-
Usa la funzione
waitpid
per monitorare lo stato del processo figlio in C - Usa le macro per visualizzare lo stato di attesa del processo figlio in C
Questo articolo mostrerà diversi metodi su come utilizzare la funzione waitpid
in C.
Usa la funzione waitpid
per monitorare lo stato del processo figlio in C
Nei sistemi basati su Unix, esiste la nozione di un processo che è semplicemente un’istanza in esecuzione di un programma. Il processo può creare altri processi usando la chiamata di sistema fork
ed eseguire la parte data del codice. Notare che, per questo argomento, le chiamate di sistema sono servizi del sistema operativo forniti all’utente come funzioni in stile C. In genere, in molti scenari, è necessario un programma per monitorare i processi che ha creato chiamati figli. La famiglia di funzioni wait
è quella che fornisce questa funzionalità e waitpid
è una di queste.
La chiamata di sistema wait
ha molteplici limitazioni e per coprire caratteristiche più avanzate, è necessario utilizzare la funzione waitpid
. Vale a dire, se un processo crea più figli e il genitore ha bisogno di monitorare un bambino specifico, solo waitpid
può farlo. Nell’esempio seguente, implementiamo una funzione denominata spawnChild
che crea un nuovo processo figlio ed esegue un programma diverso. Per una buona dimostrazione dell’esempio, stiamo eseguendo un programma top
(disponibile su quasi tutti i sistemi basati su Unix) che è in esecuzione fino a quando l’utente non lo termina. Una volta che la funzione ritorna nel processo genitore, memorizziamo un ID processo figlio e lo passiamo alla funzione waitpid
per monitorare lo stato.
Il waitpid
accetta tre argomenti, il primo dei quali è il numero di identificazione del processo (pid). Il PID può avere più valori predefiniti con effetti diversi, ma in questo caso menzioneremo solo -1
e >0
. Il valore -1
può essere passato per monitorare qualsiasi processo figlio che cambia prima il proprio stato, che viene utilizzato per implementare la funzionalità wait
. >0
implica che il valore dovrebbe essere l’ID del processo effettivo che è stato restituito dalla funzione fork
, che a sua volta viene utilizzata per monitorare solo un processo figlio specifico. Il secondo argomento è di tipo puntatore int
e dovremmo dichiarare una variabile intera per passare il suo indirizzo alla funzione. waitpid
, d’altra parte, memorizzerà le informazioni sullo stato del figlio nella variabile int
data, che poi può essere decodificata usando le macro predefinite. L’ultimo argomento è di tipo int
, ed è usato per specificare alcuni eventi del processo figlio da monitorare oltre a quelli predefiniti.
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
pid_t spawnChild(const char* program, char** arg_list) {
pid_t ch_pid = fork();
if (ch_pid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (ch_pid > 0) {
printf("spawn child with pid - %d\n", ch_pid);
return ch_pid;
} else {
execvp(program, arg_list);
perror("execve");
exit(EXIT_FAILURE);
}
}
int main(void) {
const char* args[] = {"top", NULL, NULL};
pid_t child;
int wstatus;
child = spawnChild("top", args);
if (waitpid(child, &wstatus, WUNTRACED | WCONTINUED) == -1) {
perror("waitpid");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
Usa le macro per visualizzare lo stato di attesa del processo figlio in C
Notare che il processo genitore viene sospeso quando viene chiamata la funzione waitpid
e non riprende l’esecuzione finché il processo figlio monitorato non cambia stato. Il prossimo esempio mostra la chiamata waitpid
con argomenti WUNTRACED
e WCONTINUED
, il che implica che un genitore controlla se il bambino è stato fermato o continuato dai segnali corrispondenti. Inoltre, abbiamo implementato la funzione printWaitStatus
che può essere chiamata per stampare lo stato figlio recuperato. Si noti che sta usando macro di tipo W*
definite nell’intestazione <sys/wait.h>
per estrarre le informazioni codificate dalla variabile intera status
.
Esistono alcune definizioni condizionali del preprocessore poiché non tutte le macro sono disponibili su tutte le piattaforme, assicurando così che la funzione sia portabile e venga compilata correttamente a prescindere.
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
pid_t spawnChild(const char* program, char** arg_list) {
pid_t ch_pid = fork();
if (ch_pid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (ch_pid > 0) {
printf("spawn child with pid - %d\n", ch_pid);
return ch_pid;
} else {
execvp(program, arg_list);
perror("execve");
exit(EXIT_FAILURE);
}
}
void printWaitStatus(int status) {
if (WIFEXITED(status)) {
printf("child exited, status=%d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("child killed by signal %d (%s)", WTERMSIG(status),
strsignal(WTERMSIG(status)));
#ifdef WCOREDUMP
if (WCOREDUMP(status)) printf(" (core dumped)");
#endif
printf("\n");
} else if (WIFSTOPPED(status)) {
printf("child stopped by signal %d (%s)\n", WSTOPSIG(status),
strsignal(WSTOPSIG(status)));
#ifdef WIFCONTINUED
} else if (WIFCONTINUED(status)) {
printf("child continued\n");
#endif
} else {
printf("status=%x\n", (unsigned int)status);
}
}
int main(void) {
const char* args[] = {"top", NULL, NULL};
pid_t child;
int wstatus;
child = spawnChild("top", args);
if (waitpid(child, &wstatus, WUNTRACED | WCONTINUED) == -1) {
perror("waitpid");
exit(EXIT_FAILURE);
}
printWaitStatus(wstatus);
exit(EXIT_SUCCESS);
}
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.
LinkedIn Facebook