为什么我的信号处理程序不仅等待子进程?
why my signal handler wait no just child process?
我的代码是一个多进程并发服务器进程,它使用系统 V 消息队列与客户端进程通信,一个客户端与一个子进程。首先我想要等待子进程当我用 SIG_IGN 设置 SIGCHLD 处理程序时不使用任何 more.and,程序可以正常工作,但是当我捕获 SIGCHLD 时总是出错, 错误是客户端进程在 mesrcv 系统调用中被阻塞,这意味着服务器不向客户端发送消息。second,当我输入^\退出我的客户端进程时,服务器进程退出,我把它变成了一个守护进程,并让它 运行 永远在背景中,所以我想也许 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)='[=11=]';
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()
被打断并需要再次呼叫。
根据 the POSIX msgrcv()
documentation:
ERRORS
The msgrcv()
function shall fail if:
...
[EINTR] The msgrcv()
function was interrupted by a signal.
注意 the Linux msgrcv()
man page 指出:
If no message of the requested type is available and IPC_NOWAIT
isn't
specified in msgflg
, the calling process is blocked until one of the
following conditions occurs:
A message of the desired type is placed in the queue.
The message queue is removed from the system. In this case, the system call fails with errno
set to EIDRM
.
The calling process catches a signal. In this case, the system call fails with errno
set to EINTR
. (msgrcv()
is never automatically
restarted after being interrupted by a signal handler, regardless of
the setting of the SA_RESTART
flag when establishing a signal
handler.)
这种代码风格实现了什么:
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;
}
...
}
我的代码是一个多进程并发服务器进程,它使用系统 V 消息队列与客户端进程通信,一个客户端与一个子进程。首先我想要等待子进程当我用 SIG_IGN 设置 SIGCHLD 处理程序时不使用任何 more.and,程序可以正常工作,但是当我捕获 SIGCHLD 时总是出错, 错误是客户端进程在 mesrcv 系统调用中被阻塞,这意味着服务器不向客户端发送消息。second,当我输入^\退出我的客户端进程时,服务器进程退出,我把它变成了一个守护进程,并让它 运行 永远在背景中,所以我想也许 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)='[=11=]';
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()
被打断并需要再次呼叫。
根据 the POSIX msgrcv()
documentation:
ERRORS
The
msgrcv()
function shall fail if:...
[EINTR] The
msgrcv()
function was interrupted by a signal.
注意 the Linux msgrcv()
man page 指出:
If no message of the requested type is available and
IPC_NOWAIT
isn't specified inmsgflg
, the calling process is blocked until one of the following conditions occurs:
A message of the desired type is placed in the queue.
The message queue is removed from the system. In this case, the system call fails with
errno
set toEIDRM
.The calling process catches a signal. In this case, the system call fails with
errno
set toEINTR
. (msgrcv()
is never automatically restarted after being interrupted by a signal handler, regardless of the setting of theSA_RESTART
flag when establishing a signal handler.)
这种代码风格实现了什么:
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;
}
...
}