fork和usleep中的错误

时间:2014-04-23 20:58:32

标签: c fork usleep

我写这段代码: http://ideone.com/cNypUb

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

void signchld (int signal){
    fprintf (stderr, "[X] child exited\n");
}


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] %d\n",i);
            exit(0);
            fprintf (stderr, "[C2] %d\n",i);
        }else if(f>0){
            fprintf (stderr, "[P1] %d\n",i);
            usleep(20000000);
        fprintf (stderr, "[P2] %d\n",i);
        }
    }
    return 0;
}

但是[p2]每3秒运行一次,然后运行下一个循环

我希望看到这个输出:

[P1] 0
[C1] 0
[X] child exited

20秒后

[P2] 0
[P1] 1
[C1] 1
[X] child exited

4 个答案:

答案 0 :(得分:2)

信号处理程序signchld()会中断父项usleep(),我们可以通过替换

来证明
usleep(20000000);

if (usleep(20000000) < 0) {
    if (errno == EINTR)
        fprintf (stderr, "[PX] usleep() interrupted by a signal\n");
}

(当然还包括errno.h)。这将打印

[P1] 0
[C1] 0
[X] child exited
[PX] usleep() interrupted by a signal
[P2] 0
[P1] 1

等等。

在我的系统(GNU / Linux)上,usleep()的手册页读取:

  

4.3BSD,POSIX.1-2001。 POSIX.1-2001声明此函数已废弃;使用nanosleep(2)代替。 POSIX.1-2008删除了usleep()的规范。

     

SUSv2和POSIX.1-2001仅记录了EINVAL错误返回。

答案 1 :(得分:1)

您看到父进程在您预期的20秒之前醒来是因为退出的孩子已经发送了您已注册处理的SIGCHLD信号。那个信号过早地唤醒了usleep()。它返回-1并将errno设置为EINTR。

答案 2 :(得分:1)

检查usleep()的返回值。它肯定是EINTR,如手册页中所定义:http://linux.die.net/man/3/usleep

您需要在SIGCHLD处理程序(http://linux.die.net/man/2/wait)中添加wait()调用。

另请注意,未定义哪个进程在fork()之后首先运行。即使它们是父母和孩子,它们也是由操作系统独立安排的。此外,usleep()保证睡眠时间不小于传递给它的次数,除非被中断。它确实保证当时进程会被唤醒,但通常它会非常接近。

请勿尝试使用usleep()或其任何变体进行进程同步。使用正确的IPC例程。

答案 3 :(得分:1)

usleep函数不能接受值超过1,000,000的参数 usleep(20000000)肯定会引起不可预测的行为。