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

时间:2017-10-08 10:53:34

标签: c unix signals message-queue

我的代码是一个多进程并发服务器进程,它使用系统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;
}

1 个答案:

答案 0 :(得分:1)

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

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

你没有正确处理msgrcv()被打断并需要再次被召唤。

the POSIX msgrcv() documentation

  

<强>错误

     

msgrcv()函数在以下情况下失败:

     

...

     

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

注意the Linux msgrcv() man page州:

  

如果没有所请求类型的消息可用且IPC_NOWAIT不是   在msgflg中指定,调用进程被阻塞,直到其中一个   发生以下情况:

     
      
  • 将所需类型的消息放入队列中。

  •   
  • 消息队列已从系统中删除。在这种情况下,系统调用失败,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;
    }
    ...
}