我是否可以在C中使用wait(&;status)和loop清理具有相同父进程的多个子进程?
我正在编写一个程序,可以从文件中读取我是否可以在C中使用wait(&;status)和loop清理具有相同父进程的多个子进程?,c,process,fork,wait,system-calls,C,Process,Fork,Wait,System Calls,我正在编写一个程序,可以从文件中读取linux命令,并使用fork()和execvp()并行运行这些命令,并且运行良好 while((current = GetNextCommand(current)) != NULL){ char currentCommand[WIDTH - 1]; current->active = true; strcpy(currentCommand, current->command
linux
命令,并使用fork()
和execvp()
并行运行这些命令,并且运行良好
while((current = GetNextCommand(current)) != NULL){
char currentCommand[WIDTH - 1];
current->active = true;
strcpy(currentCommand, current->command);
int j=0;
int ctr=0;
char newString[LENGTH][WIDTH];
for(int i = 0; i <= strlen(currentCommand); i++){
// if space or NULL found, assign NULL into newString[ctr]
if(currentCommand[i]==' '|| currentCommand[i]=='\0')
{
newString[ctr][j]='\0';
ctr++; //for next word
j=0; //for next word, init index to 0
}
else
{
newString[ctr][j] = currentCommand[i];
j++;
}
}
char *exe[ctr + 1];
for(int i = 0; i < ctr; i++){
exe[i] = strdup(newString[i]);
}
exe[ctr] = NULL;
t = clock();
clock_gettime(CLOCK_MONOTONIC, &start);
current->starttime = start.tv_sec;
current->PID = (pid = fork());
if(pid < 0){
fprintf(stderr, "fork Failed\n"); //output in stderr if fork fails and return
exit(1);
}
else if(pid == 0){
execvp(exe[0], exe);
//fails
exit(2);
}
}
在父进程中,我需要获取每个子进程的运行时间,如果命令的运行时间大于2秒,则重新运行该命令。如果命令的运行时间大于2,我将继续运行它,直到用户使用kill-sig pid
或pkill sleep
终止进程。我使用for循环并设置相应的等待次数(&status)。在我的文件中,sleep 3
和sleep 10
将大于2秒。当sleep 3
进程完成其工作后,它将返回到父进程,并且sleep 10
仍在运行。当我现在使用pkillsleep
时,它会很好,因为sleep 10
将继续在父进程中运行。但是,当它们都从子进程退出并且我使用kill-sigpid
时,整个程序退出。因此,在这种情况下,我如何同时运行它们(sleep3
和sleep10
)
for(int i = 0; i < nodeIndex - 1; i++){
int status;
int pid = wait(&status);
clock_gettime(CLOCK_MONOTONIC, &finish);
CommandNode* cNode;
cNode = FindCommand(head->nextCommandPtr, pid);
elapsed = finish.tv_sec - cNode->starttime;
printf("%ld\n", elapsed);
if(elapsed < 2){
cNode->active = false;
}
else{
char rerunCommand[WIDTH - 1];
strcpy(rerunCommand, cNode->command);
int j=0;
int ctr=0;
char newString[LENGTH][WIDTH];
for(int i = 0; i <= strlen(rerunCommand); i++){
// if space or NULL found, assign NULL into newString[ctr]
if(rerunCommand[i]==' '|| rerunCommand[i]=='\0')
{
newString[ctr][j]='\0';
ctr++; //for next word
j=0; //for next word, init index to 0
}
else
{
newString[ctr][j] = rerunCommand[i];
j++;
}
}
char *exe[ctr + 1];
for(int i = 0; i < ctr; i++){
exe[i] = strdup(newString[i]);
}
exe[ctr] = NULL;
while(elapsed > 2){
int pid2;
t = clock();
clock_gettime(CLOCK_MONOTONIC, &start);
cNode->starttime = start.tv_sec;
cNode->PID = (pid2 = fork());
if(pid2 < 0){
fprintf(stderr, "fork Failed"); //output in stderr if fork fails and return
exit(1);
}
else if(pid2 == 0){
printf("What happened here.\n");
execvp(exe[0], exe);
exit(2);
}
else{
wait(&status);
clock_gettime(CLOCK_MONOTONIC, &finish);
elapsed = finish.tv_sec - cNode->starttime;
if(elapsed > 2) {
printf("What is this: %d %d\n", pid2, cNode->PID);
}
}
}
}
}
for(int i=0;inextCommandPtr,pid);
运行时间=finish.tv_sec-cNode->starttime;
printf(“%ld\n”,已过);
如果(经过时间<2){
cNode->active=false;
}
否则{
字符重新取消命令[WIDTH-1];
strcpy(重新取消命令,cNode->command);
int j=0;
int ctr=0;
char newString[长度][宽度];
对于(int i=0;i 2){
int-pid2;
t=时钟();
时钟获取时间(时钟单调和开始);
cNode->starttime=start.tv\u秒;
cNode->PID=(pid2=fork());
if(pid2<0){
fprintf(stderr,“fork Failed”);//如果fork失败,则在stderr中输出并返回
出口(1);
}
else if(pid2==0){
printf(“这里发生了什么事。\n”);
execvp(exe[0],exe);
出口(2);
}
否则{
等待(&状态);
时钟获取时间(时钟单调,完成);
运行时间=finish.tv_sec-cNode->starttime;
如果(经过时间>2){
printf(“这是什么:%d%d\n”,pid2,cNode->PID);
}
}
}
}
}
关于标题中的问题:
是的,您可以循环,直到返回的值为-1是,这确实是一种正确的方法,可以确保您的所有孩子在继续之前都已完成:
pid_t pid;
...
while((pid = wait(NULL)) >= 0)
printf("child pid=%d ended.\n", pid); /* or whatever you want */
/* no more children active after this point, you don't need
* to check the value of errno, except if you allow this
* process to be interrupted by a signal. */
这是僵尸进程的老传统(就像行尸走肉电影的标题):僵尸进程是一个已退出(2)ed且父进程未等待(2)ed的进程。它释放了所有资源,除了进程表条目(存储其退出代码和记帐记录)之外。这样,当父进程执行wait(2)
系统调用时,内核可以导航其子进程表,并检查是否必须返回错误(如果列表为空),或者是否有某个子进程已结束并可以将其exit(2)
代码返回父进程。如果您之前已经创建了fork(2)
,则只能正确使用wait(2)
,wait(2)
,如果您没有创建子进程,则发出错误信号
要获取子系统的运行时间,您需要使用一个备用系统调用来wait(2)
(wait3(2)
或wait4(2)
,根据FreeBSD手册页,在linux上有类似的系统调用)
试试这个简单的例子:
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#define N 7
#define PARENT_SLEEP 30
#define CHILD_MAXSLEEP 60
int main()
{
int i;
pid_t mypid = getpid();
for(i = 0; i < N; i++) {
pid_t chpid = fork();
switch (chpid) {
case -1: /* error */
fprintf(stderr,
"Parent [pid=%d]: fork: %s\n",
mypid,
strerror(errno));
goto out; /* we want to break the loop */
case 0: /* child */
/* reinit mypid to reflect proper value */
mypid = getpid();
printf("Child [pid=%d]: start\n", mypid);
/* we initialize random module after fork, so
* all children don't get the same random
* sequence. Probably all of them will take
* the same value for the time, so we use also
* the pid for the seed to be different for
* each child. */
srandom( mypid ^ time(NULL) );
/* a random time between 1 and CHILD_MAXSLEEP */
int myrandom = random() % CHILD_MAXSLEEP + 1;
printf("Child [pid=%d]: wait for %d secs.\n",
mypid, myrandom);
sleep( myrandom );
printf("Child [pid=%d]: exiting with code=%d\n",
mypid, myrandom);
exit( myrandom );
default: /* parent */
printf("Parent[pid=%d]: I have started"
" child (pid = %d)\n", mypid, chpid);
break;
} /* switch */
} /* for */
out:
/* if you put a delay here, before doing wait()s,
* and you execute a ps(1) command before the parent
* begins to make waits, and some of the children have
* already died, you'll see the zombie processes
* (they are marked with a Z in status) */
printf("Parent [pid=%d]: sleeping for %ds.\n",
mypid, PARENT_SLEEP);
sleep(PARENT_SLEEP);
printf("Parent [pid=%d]: beginning to wait.\n",
mypid);
int status;
pid_t child;
while ((child = wait(&status)) >= 0) {
printf("Parent[pid=%d]: "
"detected exit(%d) from "
"child(pid=%d)\n",
mypid,
WEXITSTATUS(status),
child);
}
printf("Parent[pid=%d]: exiting\n", mypid);
exit(0);
} /* main */
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义n7
#定义父母睡眠30
#定义CHILD_maxleep 60
int main()
{
int i;
pid_t mypid=getpid();
对于(i=0;i#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#define N 7
#define PARENT_SLEEP 30
#define CHILD_MAXSLEEP 60
int main()
{
int i;
pid_t mypid = getpid();
for(i = 0; i < N; i++) {
pid_t chpid = fork();
switch (chpid) {
case -1: /* error */
fprintf(stderr,
"Parent [pid=%d]: fork: %s\n",
mypid,
strerror(errno));
goto out; /* we want to break the loop */
case 0: /* child */
/* reinit mypid to reflect proper value */
mypid = getpid();
printf("Child [pid=%d]: start\n", mypid);
/* we initialize random module after fork, so
* all children don't get the same random
* sequence. Probably all of them will take
* the same value for the time, so we use also
* the pid for the seed to be different for
* each child. */
srandom( mypid ^ time(NULL) );
/* a random time between 1 and CHILD_MAXSLEEP */
int myrandom = random() % CHILD_MAXSLEEP + 1;
printf("Child [pid=%d]: wait for %d secs.\n",
mypid, myrandom);
sleep( myrandom );
printf("Child [pid=%d]: exiting with code=%d\n",
mypid, myrandom);
exit( myrandom );
default: /* parent */
printf("Parent[pid=%d]: I have started"
" child (pid = %d)\n", mypid, chpid);
break;
} /* switch */
} /* for */
out:
/* if you put a delay here, before doing wait()s,
* and you execute a ps(1) command before the parent
* begins to make waits, and some of the children have
* already died, you'll see the zombie processes
* (they are marked with a Z in status) */
printf("Parent [pid=%d]: sleeping for %ds.\n",
mypid, PARENT_SLEEP);
sleep(PARENT_SLEEP);
printf("Parent [pid=%d]: beginning to wait.\n",
mypid);
int status;
pid_t child;
while ((child = wait(&status)) >= 0) {
printf("Parent[pid=%d]: "
"detected exit(%d) from "
"child(pid=%d)\n",
mypid,
WEXITSTATUS(status),
child);
}
printf("Parent[pid=%d]: exiting\n", mypid);
exit(0);
} /* main */
$ a.out
Parent[pid=81452]: I have started child (pid = 81453)
Parent[pid=81452]: I have started child (pid = 81454)
Parent[pid=81452]: I have started child (pid = 81455)
Parent[pid=81452]: I have started child (pid = 81456)
Child [pid=81453]: start
Child [pid=81453]: wait for 34 secs.
Child [pid=81455]: start
Child [pid=81455]: wait for 56 secs.
Child [pid=81456]: start
Child [pid=81456]: wait for 42 secs.
Parent[pid=81452]: I have started child (pid = 81457)
Parent[pid=81452]: I have started child (pid = 81458)
Parent[pid=81452]: I have started child (pid = 81459)
Parent [pid=81452]: sleeping for 30s.
Child [pid=81454]: start
Child [pid=81454]: wait for 9 secs.
Child [pid=81457]: start
Child [pid=81457]: wait for 58 secs.
Child [pid=81458]: start
Child [pid=81458]: wait for 30 secs.
Child [pid=81459]: start
Child [pid=81459]: wait for 14 secs.
Child [pid=81454]: exiting with code=9
Child [pid=81459]: exiting with code=14
Child [pid=81458]: exiting with code=30
Parent [pid=81452]: beginning to wait. <<<<< before this message, you can see Zombie processes.
Parent[pid=81452]: detected exit(14) from child(pid=81459)
Parent[pid=81452]: detected exit(30) from child(pid=81458)
Parent[pid=81452]: detected exit(9) from child(pid=81454)
Child [pid=81453]: exiting with code=34
Parent[pid=81452]: detected exit(34) from child(pid=81453)
Child [pid=81456]: exiting with code=42
Parent[pid=81452]: detected exit(42) from child(pid=81456)
Child [pid=81455]: exiting with code=56
Parent[pid=81452]: detected exit(56) from child(pid=81455)
Child [pid=81457]: exiting with code=58
Parent[pid=81452]: detected exit(58) from child(pid=81457)
Parent[pid=81452]: exiting
$ _