繁体   English   中英

为什么我的信号处理程序不等待子进程?

[英]why my signal handler wait no just child process?

我的代码是一个多进程并发服务器进程,它使用system V消息队列与客户端进程通信,一个客户端一个子进程。 首先我想要等待不再使用的子进程。当我用 SIG_IGN 设置 SIGCHLD 处理程序时,程序可以正常工作,但是当我捕获 SIGCHLD 时总是出错,错误是客户端进程在 mesrcv 系统调用中阻塞,这意味着服务器不要向客户端发送消息 其次当我输入 ^\\ 退出我的客户端进程时服务器进程就出去了,我让它成为一个守护进程并让它永远在后台运行,所以我想也许 waitpid 调用是等待本身?虽然我认为这是不可能的

//this is signal handler
void handler(int sig){
    waitpid(-1,NULL,WNOHANG);
}
//in main
//my first step is make it become a daemon(fork twice)
//my first step is using record lock to ensure only one running
//then set signal handler and process message send by client
if(signal(SIGCHLD,SIG_IGN)==SIG_ERR){
    //because its a daemon,so no tty and redirct stdin,stdout,stderr to /dev/null
    syslog(LOG_ERR|LOG_USER,"set signal handler failed");
    return errno;
}
//now process the client request ,client message contant a client sysV message queue id and a filename,server report the file whether exist
int pid;
while((rcv_size=msgrcv(srvmqid,&srvbuf,1024,0)!=-1){
    if(0==rcv_size)
        continue;
    if((pid=fork())<=0){
        clibuf.mtype=srvbuf.mtype;
        climsqid=strtol(srvbuf.filename,&filename,10);
        if((fd=open(filename,O_RDONLY)==-1)
            snprintf(clibuf.filename,"file doesn't exist\n");
        else{
            snprintf(clibuf.filename,"file exist\n");
            close(fd);
        }
        if(msgsnd(climsqid,&clibuf,1024,0)==-1)
            syslog(LOG_ERR,"send message to client pid:%d failed,srvbuf.mtype);
        if(pid==0)    //if pid<0,then no child process is created
            exit(0);
    }

}

客户端进程的核心代码如下

int main(int argc,char*argv[]){
//first ,i create the client message queue and open public serve message queue,then send struct msgbuf struct to server,the mtype is pid,the buffer behind mtype is composed by client message queue key and filename(no space between them)
while(1){
if(msgsnd(sermsqid,&sndbuf,1024,0)!=-1){
    if(msgrcv(climsqid,&rcvbuf,1024,0,0)!=-1)
        printf("type:%ld,file state:%s\n",rcvbuf.mtype,rcvbuf.filename);
    else
        printf("receive message failed\n");
}
printf("input a filename you want to search:(^e to quit)");
fgets(filename,1024,stdin);
if(filename[0]==5)//^e is 5
    break;
filename[strlen(filename)-1)='\0';
snprintf(sndbuf.filename,1024,"%d%s",climsqid,filename);
}
msgctl(climsqid,IPC_RMID,NULL);
return errno;
}

此代码不允许错误处理或在中断后重新启动调用:

while((rcv_size=msgrcv(srvmqid,&srvbuf,1024,0)!=-1){
    ...

您没有正确处理msgrcv()被中断并需要再次调用。

根据POSIX msgrcv()文档

错误

如果出现以下情况, msgrcv()函数将失败:

...

[EINTR] msgrcv()函数被信号中断。

请注意Linux msgrcv()手册页指出:

如果没有请求类型的消息可用并且msgflg未指定IPC_NOWAIT ,则调用进程将被阻止,直到发生以下情况之一:

  • 所需类型的消息放置在队列中。

  • 消息队列从系统中删除。 在这种情况下,系统调用失败, errno设置为EIDRM

  • 调用进程捕获一个信号。 在这种情况下,系统调用失败, errno设置为EINTR msgrcv()在被信号处理程序中断后永远不会自动重新启动,无论在建立信号处理程序时SA_RESTART标志的设置如何。)

这种风格的代码实现了什么:

while((rcv_size=msgrcv(srvmqid,&srvbuf,1024,0)!=-1){

所以你节省了一些代码行。 如果您销售一本包含大量代码的教科书,节省的代码行意味着每本书少几页,节省几分钱。 超过足够的副本,这为出版商的游泳池买单。

把所有东西都塞进这样的条件中真的非常糟糕。 显式使用多行代码没有任何好处:

for ( ;; )
{
    ssize_t rcv_size;
    do
    {
        errno = 0;
        rcv_size = msgrcv(...);
    }
    while ( ( -1 == rcv_size ) && ( EINTR == errno ) );

    if ( -1 == rcv_size )
    {
        perror( "msgrcv()" );
        break;
    }
    else if ( 0 == rcv_size )
    {
        continue;
    }
    ...
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM