0

我写了这段代码: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

4 回答 4

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 错误返回。

于 2014-04-23T21:14:21.813 回答
1

您看到父进程早于您预期的 20 秒唤醒,这是因为退出子进程已传递您已注册处理的 SIGCHLD 信号。usleep()该信号过早唤醒。它返回 -1 并将 errno 设置为 EINTR。

于 2014-04-23T21:17:56.593 回答
1

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

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

另请注意,未定义在fork(). 即使它们是父子关系,它们也是由操作系统独立调度的。此外,usleep()保证睡眠不小于传递给它的 u 秒数,除非被中断。它不保证该过程会在那个时候唤醒,尽管通常它会非常接近。

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

于 2014-04-23T21:31:16.740 回答
1

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

于 2014-07-07T23:55:34.050 回答