Devi capire come funzionano insieme fork ed execv.
- fork() crea un duplicato del processo corrente, restituendo 0 a child, childpid a parent
- fork() può fallire, e restituisce -1 in caso di errore, controllalo
- execv() sostituisce il processo genitore duplicato con un nuovo processo
- l'abbinamento tipico fork/exec sostituisce il processo figlio con un nuovo processo
- spesso si esegue il fork di più di un bambino e si desidera che funzionino contemporaneamente
- Tuttavia, hai chiesto che vengano eseguiti consecutivamente, cioè uno dopo l'altro
- quindi, devi attendere il completamento del primo prima di iniziare il secondo
- quindi devi usare qualche variante di wait(), l'esempio sotto usa waitpid() per aspettare un bambino specifico
Hai bisogno di stdlib per uscire (nel caso in cui execv fallisca) e errno, per stampare il motivo,
//I'm trying to run two executables consecutively using this c code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
Potresti voler esaminare il motivo per cui tuo figlio è uscito (core dump, segnale, uscita normale), quindi ho aggiunto questa funzione,
#include <sys/types.h>
#include <sys/wait.h>
//WIFEXITED(status) returns true if the child terminated normally, that is, by calling exit(3) or _exit(2), or by returning from main().
//WEXITSTATUS(status) returns the exit status of the child. This consists of the least significant 8 bits of the status argument that the child specified in a call to exit(3) or _exit(2) or as the argument for a return statement in main(). This macro should only be employed if WIFEXITED returned true.
//WIFSIGNALED(status) returns true if the child process was terminated by a signal.
//WTERMSIG(status) returns the number of the signal that caused the child process to terminate. This macro should only be employed if WIFSIGNALED returned true.
//WCOREDUMP(status) returns true if the child produced a core dump. This macro should only be employed if WIFSIGNALED returned true. This macro is not specified in POSIX.1-2001 and is not available on some UNIX implementations (e.g., AIX, SunOS). Only use this enclosed in #ifdef WCOREDUMP ... #endif.
//WIFSTOPPED(status) returns true if the child process was stopped by delivery of a signal; this is only possible if the call was done using WUNTRACED or when the child is being traced (see ptrace(2)).
//WSTOPSIG(status) returns the number of the signal which caused the child to stop. This macro should only be employed if WIFSTOPPED returned true.
//WIFCONTINUED(status) (since Linux 2.6.10) returns true if the child process was resumed by delivery of SIGCONT.
int
exitreason(pid_t cid, int status)
{
if( WIFEXITED(status) )
{
printf("child %d terminated normally, that is, by calling exit(3) or _exit(2), or by returning from main().\n",cid);
if( WEXITSTATUS(status) )
{
printf("child %d exit status %d. This consists of the least significant 8 bits of the status argument that the child specified in a call to exit(3) or _exit(2) or as the argument for a return statement in main().\n",cid,WEXITSTATUS(status));
}
}
if( WIFSIGNALED(status) )
{
printf("child %d process was terminated by a signal.\n",cid);
if( WTERMSIG(status) )
{
printf("child %d signal %d that caused the child process to terminate.\n",cid,WTERMSIG(status));
}
if( WCOREDUMP(status) )
{
printf("child %d produced a core dump. WCOREDUMP() is not specified in POSIX.1-2001 and is not available on some UNIX implementations (e.g., AIX, SunOS). Only use this enclosed in #ifdef WCOREDUMP ... #endif.\n",cid);
}
}
if( WIFSTOPPED(status) )
{
printf("child %d process was stopped by delivery of a signal; this is only possible if the call was done using WUNTRACED or when the child is being traced (see ptrace(2)).\n",cid);
if( WSTOPSIG(status) )
{
printf("child %d number of the signal which caused the child to stop.\n",cid);
}
}
if( WIFCONTINUED(status) )
{
printf("child %d process was resumed by delivery of SIGCONT.\n");
}
}
Ed ecco il tuo programma annotato con commenti che spiegano quali sezioni di codice vengono elaborate dal genitore e quali dal/i figlio/i.
int main (int argc, char *argv[])
{
char proc1[] = "/bin/echo"; //"./prcs1";
char proc2[] = "/bin/echo"; //"./prcs2";
pid_t cid1, cid2, cidX;
int status=0;
int waitoptions = 0;
//WNOHANG return immediately if no child has exited.
//WUNTRACED also return if a child has stopped (but not traced via ptrace(2)). Status for traced children which have stopped is provided even if this option is not specified.
//WCONTINUED also return if a stopped child has been resumed by delivery of SIGCONT.
int res;
if( (cid1 = fork()) == 0 ) //child1
{
printf("in child1\n");
if( (res = execv(proc1, &argv[1])) < 0 ) // GIVE ADDRESS OF 2nd element as starting point to skip source.txt
{
printf("error: child1: %d exec failed %d\n", cid1, errno);
printf("error: cannot execv %s\n",proc1);
exit(91); //must exit child
}
}
else if( cid1 > 0 ) //cid>0, parent, waitfor child
{
cidX = waitpid(cid1, &status, waitoptions);
printf("child1: %d res %d\n", cid1, res);
exitreason(cid1, status);
}
else //cid1 < 0, error
{
printf("error: child1 fork failed\n");
}
if( (cid2 = fork()) == 0 ) //child2
{
printf("in child2\n");
if( (res = execv(proc2, &argv[1])) < 0 ) // GIVE ADDRESS OF 2nd element as starting point to skip source.txt
{
printf("error: child2: %d exec failed %d\n", cid2, errno);
printf("error: cannot execv %s\n",proc2);
exit(92); //must exit child
}
}
else if( cid2 > 0 ) //cid>0, parent, waitfor child
{
cidX = waitpid(cid2, &status, waitoptions);
printf("child2: %d res %d\n", cid2, res);
exitreason(cid2, status);
}
else //cid2 < 0, error
{
printf("error: child2 fork failed\n");
}
}
Hai un paio di problemi. Innanzitutto, se vuoi eseguire solo due programmi, devi solo chiamare fork()
una volta. Quindi eseguire un programma nel processo padre e uno nel figlio. Secondo, stai costruendo il argv
array da passare a execv
in modo errato. La prima voce dovrebbe essere il nome dell'eseguibile. Fai qualcosa come:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(int argc, char **argv)
{
pid_t i = fork();
if (i == 0)
{
execv("./prcs1", (char *[]){ "./prcs1", argv[1], NULL });
_exit(1);
}
else if (i > 0)
{
execv("./prcs2", (char *[]){ "./prcs2", argv[0], NULL });
_exit(2);
}
else
{
perror("fork failed");
_exit(3);
}
}
Nota che questo esempio non controlla gli errori.
Non hai letto molto su fork() immagino.
quando chiami fork()
, crea un processo figlio che eseguirà lo stesso codice da fork.
fork()
restituisce tre tipi di valori
- negativo che mostra un errore
- positivo che indica che sei nel processo genitore e il valore mostra l'ID childprosess
- zero che indica che sei nel processo figlio.
il tuo codice dovrebbe assomigliare a questo.
#include <stdio.h>
#include <unistd.h>
int main (int argc, char *argv[])
{
int ret = fork();
if(ret==0)
{
//child process
execv("./prcs1", &argv[1]); // GIVE ADDRESS OF 2nd element as starting point to skip source.txt
printf("EXECV Failed from child\n");
}
else if(ret>0)
{
//parent process
execv("./prcs2", argv);
printf("EXECV Failed from parent\n");
}
else
{
//you will come here only if fork() fails.
printf("forkFailed\n");
}
return 0;
}