- 论坛徽章:
- 0
|
10可用积分
有一个获取进程个数的程序:
sprintf(Cmd, "ps -ef|grep %s|grep %s|wc -l", prog, entr);
fp = popen(Cmd, "r");
if(fp == NULL) {
printf("打开管道[%s]错\n", Cmd);
return -1;
}
memset(buff, 0, sizeof(buff));
if ( fgets(buff, 256, fp) == NULL ) {
perror( "fgets:" );
printf("fgets() error[%d][%ld]\n",i, (long)getpid() );
pclose( fp );
return -1;
}
。。。。。。
pclose(fp);
正常运行是没有问题的。但是如果捕获了SIGCHLD信号后,重复执行以上程序,则会不定时在fgets()
时报错:Interrupted system call(errno==4)。
完整的程序代码如下:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<string.h>
#include<signal.h>
#include<unistd.h>
#include<errno.h>
#include<sys/wait.h>
struct sigaction sa_old;
struct sigaction sa_new;
/*------------------------------------------------------------------------
Function Name : agt_chld_exit
Description : 子进程结束信号处理
Input :
_sign 捕捉到的信号
Output :
Return :
------------------------------------------------------------------------*/
void agt_chld_exit(int _sign)
{
int e = errno;
int stat = 0;
pid_t pid_tmp = 0;
while((pid_tmp = waitpid(-1, &stat, WNOHANG)) > 0)
printf("进程[%d]退出\n", pid_tmp);
errno = e;
return;
}
int
main()
{
int i=0;
FILE *fp = NULL;
char Cmd[1025];
char buff[1025];
char prog[81];
char entr[9];
int Cnt = 0;
int ret = -1;
memset(&sa_old, 0, sizeof(sa_old));
memset(&sa_new, 0, sizeof(sa_new));
signal(SIGPIPE, SIG_IGN);
if(setpgrp() < 0) {
printf( "setpgrp error.\n");
exit(1);
}
signal(SIGPIPE, SIG_IGN);
ret = sigemptyset(&sa_new.sa_mask);
if(ret != 0) {
printf( "SIGEMPTYSET RET=[%d]\n", ret);
exit(1);
}
sa_new.sa_flags = 0;
sa_new.sa_handler = agt_chld_exit;
ret = sigaddset(&sa_new.sa_mask, SIGTERM);
if(ret != 0) {
printf( "SIGADDSET(SIGTERM) RET=[%d]\n", ret);
exit(1);
}
ret = sigaddset(&sa_new.sa_mask, SIGCHLD);
if(ret != 0) {
printf("SIGADDSET RET=[%d]\n", ret);
exit(1);
}
ret = sigaction(SIGTERM, &sa_new, &sa_old);
if(ret != 0) {
printf("SIGACTION RET=[%d]\n", ret);
exit(1);
}
ret = sigaction(SIGCHLD, &sa_new, &sa_old);
if(ret != 0) {
printf("SIGACTION RET=[%d]\n", ret);
exit(1);
}
memset(prog, 0, sizeof(prog));
memset(Cmd, 0, sizeof(Cmd));
memset(entr, 0, sizeof(entr));
strcpy(prog, "aa");
strcpy(entr, "bb");
while ( 1 ) {
sprintf(Cmd, "ps -ef|grep %s|grep %s|wc -l", prog, entr);
fp = popen(Cmd, "r");
if(fp == NULL) {
printf("打开管道[%s]错\n", Cmd);
return -1;
}
memset(buff, 0, sizeof(buff));
if ( fgets(buff, 256, fp) == NULL ) {
perror( "fgets:" );
printf("fgets() error[%d][%ld]\n",i, (long)getpid() );
pclose( fp );
return -1;
}
if ( strlen(buff) <= 0 ) {
printf("fgets() buff== NULL\n" );
pclose( fp );
return -1;
}
pclose(fp);
i++;
if ( i > 30000 )
break;
}
return 0;
}
如果不捕获SIGCHLD信号(把sigaction(SIGCHLD, &sa_new, &sa_old);那段屏蔽起来),fgets()就
不会报错;一旦放开,fgets()就会不定时报错(与SIGCHLD信号处理函数agt_chld_exit()中的处理没有
关系,即使agt_chld_exit()是个空函数,一样也会报错)。
P.S,在tt.c中明明没有fork()子进程,怎么会收到SIGCHLD信号呢?是不是因为SIGCHLD是不可靠的
信号? |
最佳答案
查看完整内容
fgets 最终会使用系统调用 read,它会被信号中断,除非对该信号的处理是忽略。man read 中的说明,看 EINTR 部分。如果你捕捉 SIGCHLD,read 调用就有被中断的可能,可以自行己判断一下 errno, 然后进行相应处理。你也可以忽略掉 SIGCHLD(这是默认的行为),那就省事多了。[ 本帖最后由 win_hate 于 2007-11-23 19:19 编辑 ]
|