如何正确地等待前台/后台进程在用C我自己的壳呢? [英] How to properly wait for foreground/background processes in my own shell in C?

查看:155
本文介绍了如何正确地等待前台/后台进程在用C我自己的壳呢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

previous问题我贴我的大部分外壳code的。我的下一步是实现前台和后台流程执行和适当等待他们终止让他们不留的植物大战僵尸。

增加在后台运行它们的可能性之前,所有过程进行了在前台运行。执行与execvp任何处理结束后,对于这一点,我简单地称为等待(NULL)()。现在,我检查'和;'字符作为最后一个参数,如果它的存在,通过不调用wait(NULL),这个过程可以在后台运行愉快地在后台运行的过程中会我回到了我的外壳。

这是所有工作正常(我认为),现在的问题是,我还需要调用wait()(或者waitpid函数()?)不知何故,使后台进程不留僵尸。这是我的问题,我不知道该怎么做...

我相信我有处理SIGCHLD,做一些事情,但我还没有完全理解当发送SIGCHLD信号,因为我想还添加等待(NULL)至childSignalHandler(),但它并没有因为随着工作当我在后台执行的过程中,childSignalHandler()函数被调用,因此,等待(NULL),这意味着我不能用我的壳做任何事情,直到背景的过程结束。这是不是在后台,因为在信号处理程序中等待的运行了。

那我在这一切丢失?

最后一件事,这个练习我还需要打印的过程中地位的变化,比如终止进程的一部分。因此,在任何见解也着实AP preciated。

这是目前我的全部code:

 的#include<&stdio.h中GT;
#包括LT&;&stdlib.h中GT;
#包括LT&;&string.h中GT;
#包括LT&;&unistd.h中GT;
#包括LT&;&wait.h GT;
#包括LT&;&signal.h中GT;
#包括LT&; SYS / types.h中>#包括data.h//布尔类型定义和真/假宏
无效childSignalHandler(INT正负号){
    //
}INT主(INT ARGC,字符** argv的){
    炭bBuffer [BUFSIZ],* pArgs [10],* APTR = NULL,*特征码指针;
    布尔背景;
    ssiz​​e_t供rbytes已;
    INT aCount;
    将为pid_t PID;    //信号(SIGINT,SIG_IGN);    信号(SIGCHLD,childSignalHandler);    而(1){
    写(1,\\ E [1; 31mmyBash \\ E [1;32米#\\ E [0米,27);
    rbytes已=读(0,bBuffer,BUFSIZ-1);    如果(rbytes已== -1){
    PERROR(读);
    出口(1);
    }    bBuffer [rbytes已-1] ='\\ 0';    如果(!strcasecmp(bBuffer,退出)){
    出口(0);
    }    特征码= bBuffer;
    aCount = 0;    做{
    APTR = strsep(安培;特征码指针,);
    pArgs [aCount ++] = APTR;
    }而(APTR);    背景= FALSE;    如果(!的strcmp(pArgs [aCount-2],与&)){
    pArgs [aCount-2] = NULL;
    背景= TRUE;
    }    如果(strlen的(pArgs [0])大于1){
    PID =叉();    如果(PID == -1){
    PERROR(叉);
    出口(1);
    }    如果(PID == 0){
    execvp(pArgs [0],pArgs);
    出口(0);
    }    如果(!背景){
    等待(NULL);
    }
    }
    }    返回0;
}


解决方案

有各种选项 waitpid函数()来帮助你(从POSIX标准引号):


  

WCONTINUED


  
  

在waitpid函数()函数应当向由pid的地位,因为它从一个作业控制停止持续尚未见报道指定的任何持续的子进程的状态。


  
  

WNOHANG


  
  

如果状态没有立即由pid指定的其中一个子进程的waitpid函数()函数不得暂停调用线程的执行。


在特别WNOHANG将让你看看是否有尸体收集,而不会引起你的进程阻塞,等待尸体。


  

如果调用进程具有SA_NOCLDWAIT设置或具有SIGCHLD设置为SIG_IGN,这个过程没有unwaited,对于转化成僵尸进程的孩子,则调用线程应,直到所有的进程包含调用线程的孩子阻挡终止,等待()和waitpid函数()失败,将errno设置为[ECHILD。


您可能不希望被忽略SIGCHLD等,以及信号处理程序可能应该设置一个标志,告诉主循环哎呀,有死孩子 - 去收集尸体!

该SIGCONT和SIGSTOP信号也将是相关的你 - 它们被用来启动和停止子进程,分别为(在这种情况下,在任何速度)

我建议在看Rochkind的书或史蒂文斯的书 - 他们详细讨论这些问题。

In this previous question I posted most of my own shell code. My next step is to implement foreground and background process execution and properly wait for them to terminate so they don't stay as "zombies".

Before adding the possibility to run them in the background, all processes were running in the foreground. And for that, I simply called wait(NULL) after executing any process with execvp(). Now, I check for the '&' character as the last argument and if it's there, run the process in the background by not calling wait(NULL) and the process can run happily in the background will I'm returned to my shell.

This is all working properly (I think), the problem now, is that I also need to call wait() (or waitpid() ?) somehow so that the background process doesn't remain "zombie". That's my problem, I'm not sure how to do that...

I believe I have to handle SIGCHLD and do something there, but I have yet to fully understand when the SIGCHLD signal is sent because I tried to also add wait(NULL) to childSignalHandler() but it didn't work because as soon as I executed a process in the background, the childSignalHandler() function was called and consequently, the wait(NULL), meaning I couldn't do anything with my shell until the "background" process finished. Which wasn't running on the background anymore because of the wait in the signal handler.

What am I missing in all this?

One last thing, part of this exercise I also need to print the changes of the processes status, like process termination. So, any insight on that is also really appreciated.

This is my full code at the moment:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <wait.h>
#include <signal.h>
#include <sys/types.h>

#include "data.h" // Boolean typedef and true/false macros


void childSignalHandler(int signum) {
    //
}

int main(int argc, char **argv) {
    char bBuffer[BUFSIZ], *pArgs[10], *aPtr = NULL, *sPtr;
    bool background;
    ssize_t rBytes;
    int aCount;
    pid_t pid;

    //signal(SIGINT, SIG_IGN);

    signal(SIGCHLD, childSignalHandler);

    while(1) {
    	write(1, "\e[1;31mmyBash \e[1;32m# \e[0m", 27);
    	rBytes = read(0, bBuffer, BUFSIZ-1);

    	if(rBytes == -1) {
    		perror("read");
    		exit(1);
    	}

    	bBuffer[rBytes-1] = '\0';

    	if(!strcasecmp(bBuffer, "exit")) {
    		exit(0);
    	}

    	sPtr = bBuffer;
    	aCount = 0;

    	do {
    		aPtr = strsep(&sPtr, " ");
    		pArgs[aCount++] = aPtr;
    	} while(aPtr);

    	background = FALSE;

    	if(!strcmp(pArgs[aCount-2], "&")) {
    		pArgs[aCount-2] = NULL;
    		background = TRUE;
    	}

    	if(strlen(pArgs[0]) > 1) {
    		pid = fork();

    		if(pid == -1) {
    			perror("fork");
    			exit(1);
    		}

    		if(pid == 0) {
    			execvp(pArgs[0], pArgs);
    			exit(0);
    		}

    		if(!background) {
    			wait(NULL);
    		}
    	}
    }

    return 0;
}

解决方案

There are various options to waitpid() to help you (quotes from the POSIX standard):

WCONTINUED

The waitpid() function shall report the status of any continued child process specified by pid whose status has not been reported since it continued from a job control stop.

WNOHANG

The waitpid() function shall not suspend execution of the calling thread if status is not immediately available for one of the child processes specified by pid.

In particular, WNOHANG will allow you to see whether there are any corpses to collect without causing your process to block waiting for a corpse.

If the calling process has SA_NOCLDWAIT set or has SIGCHLD set to SIG_IGN, and the process has no unwaited-for children that were transformed into zombie processes, the calling thread shall block until all of the children of the process containing the calling thread terminate, and wait() and waitpid() shall fail and set errno to [ECHILD].

You probably don't want to be ignoring SIGCHLD, etc, and your signal handler should probably be setting a flag to tell your main loop "Oops; there's dead child - go collect that corpse!".

The SIGCONT and SIGSTOP signals will also be of relevance to you - they are used to restart and stop a child process, respectively (in this context, at any rate).

I'd recommend looking at Rochkind's book or Stevens' book - they cover these issues in detail.

这篇关于如何正确地等待前台/后台进程在用C我自己的壳呢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆