我编写以下代码:http://ideone.com/cNypUb
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
void signchld (int signal){
fprintf (stderr, "[X] child exitedn");
}
int main(){
signal (SIGCHLD, signchld);
int i;
for(i=0;i<=300;i++){
pid_t f;
f=fork();
if(f==0){
//child
usleep(3*1000000);
fprintf (stderr, "[C1] %dn",i);
exit(0);
fprintf (stderr, "[C2] %dn",i);
}else if(f>0){
fprintf (stderr, "[P1] %dn",i);
usleep(20000000);
fprintf (stderr, "[P2] %dn",i);
}
}
return 0;
}
但是[p2]
每3秒运行一次,然后运行下一个循环
我希望看到这个输出:
[P1] 0
[C1] 0
[X] child exited
在20秒之后
[P2] 0
[P1] 1
[C1] 1
[X] child exited
正是信号处理程序signchld()
中断了父级中的usleep()
,我们可以通过替换来证明这一点
usleep(20000000);
带有
if (usleep(20000000) < 0) {
if (errno == EINTR)
fprintf (stderr, "[PX] usleep() interrupted by a signaln");
}
(当然也包括errno.h
)。这将打印
[P1] 0
[C1] 0
[X] child exited
[PX] usleep() interrupted by a signal
[P2] 0
[P1] 1
等等
在我的系统(GNU/Linux)上,usleep()
的手册页上写着:
4.3BSD,位置.1-2001。POSIX.1-2001声明此函数已过时;请改用nanosleep(2)。POSIX.1-2008删除了usleep()的规范。
SUSv2和POSIX.1-2001只记录了EINVAL错误返回。
您可以看到父进程在您预期的20秒之前醒来,这是因为退出的子进程已经传递了您已注册要处理的SIGCHLD信号。该信号过早地唤醒usleep()
。它返回-1,并将errno设置为EINTR。
检查usleep()
的返回值。它肯定是EINTR,正如手册页中所定义的:http://linux.die.net/man/3/usleep
您需要在SIGCHLD处理程序中添加一个wait()
调用(http://linux.die.net/man/2/wait)。
还要注意的是,在fork()
之后哪个进程首先运行是未定义的。即使它们是父级和子级,它们也是由操作系统独立安排的。此外,usleep()
保证睡眠不少于传递给它的useconds数,除非被中断。它不能保证进程在那个时候会唤醒,尽管通常情况下它会非常接近。
不要尝试使用usleep()
或其任何变体进行进程同步。使用正确的仪表板组合仪表例行程序。
usleep函数不能接受值超过1000000的参数usleep(20000000)肯定会导致不可预测的行为。