Debe comprender cómo bifurcación y execv funcionan juntos.
- fork() hace un duplicado del proceso actual, devolviendo 0 al hijo, childpid al padre
- fork() puede fallar y devuelve -1 en caso de falla, compruébalo
- execv() reemplaza el proceso principal duplicado con un nuevo proceso
- el emparejamiento típico de bifurcación/ejecutivo reemplaza el proceso secundario con un nuevo proceso
- a menudo bifurcas a más de un niño y quieres que corran simultáneamente,
- sin embargo, pediste que se ejecutaran consecutivamente, es decir, uno tras otro
- por lo tanto, debe esperar a que se complete el primero antes de iniciar el segundo
- por lo tanto, debe usar alguna variante de wait(), el ejemplo a continuación usa waitpid() para esperar a un niño específico
Necesitas stdlib para salir (en caso de que execv falle), y errno, para imprimir el 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>
Es posible que desee examinar la razón por la que su hijo salió (volcado del núcleo, señal, salida normal), por lo tanto, he agregado esta función,
#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");
}
}
Y aquí está su programa anotado con comentarios que explican qué secciones de código son procesadas por el padre y cuáles por el(los) hijo(s).
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");
}
}
Tienes un par de problemas. Primero, si solo desea ejecutar dos programas, solo necesita llamar a fork()
una vez. Luego ejecute un programa en el proceso principal y otro en el secundario. Segundo, estás construyendo el argv
matriz que se pasará a execv
incorrectamente. La primera entrada debe ser el nombre del ejecutable. Haz algo como:
#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);
}
}
Tenga en cuenta que este ejemplo no comprueba errores.
Supongo que no has leído mucho sobre fork().
cuando llamas fork()
, crea un proceso secundario que ejecutará el mismo código desde la bifurcación.
fork()
devuelve tres tipos de valores
- negativo que muestra un error
- positivo que dice que está en un proceso principal y el valor muestra ID de childprosess
- cero que dice que está en un proceso secundario.
su código debería verse así.
#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;
}