1

考虑:

int main()
{
        if (fork() == 0){
            printf("a");
        }
        else{
            printf("b");
            waitpid(-1, NULL, 0);
        }
        printf("c");
        exit(0);
 }

(来自计算机系统,Bryant - O'Hallaron)。

我们被要求提供所有可能的输出序列。

我回答:acbc、abcc、bacc。但是,与解决方案 (bcac) 相比,我缺少一个输出。我认为这个输出是不可能的,因为父进程在打印 c (waitpid) 之前等待它的子进程返回。这不是真的吗?为什么?而且,在这种情况下,上面的代码和没有 waitpid 行的代码有什么区别?

4

2 回答 2

3

我看不出有什么办法bcac。起初,我预计会出现一些基于 stdio 缓冲区以意外顺序刷新的诡计。但即便如此:

孩子在输出c之前不会输出ac因此,第一个bcac必须来自父母。

c在完成之前,父级不会输出waitpid。但这要等到孩子完成后才会发生,包括在exit(). 因此,第一个c总是来自孩子。

已经实现了矛盾证明......输出不可能bcac

好吧,您可以做一件事来打乱订单。您可以在已经有一个即将退出的子进程的进程中执行该程序。如果预先存在的孩子在新孩子打印之前退出a,那么主进程将检测退出waitpid,并继续打印它的东西,并可能在孩子打印任何东西之前退出。

这是在 setuid 程序中要注意的事情:不要假设因为您的程序只创建了一个子进程,所以它只有一个子进程。如果您处于高级防御代码学习环境中,那么这个答案是有意义的。在 unix-newbie 上下文中,它似乎并不相关,最好说bcac是不可能的,即使它在技术上不正确。

于 2014-08-13T02:09:23.290 回答
1

这很棘手,但调用waitpid可以被中断(返回-1和 errno 是EINTR)。在这种情况下,父母可以c在孩子输出任何东西之前输出并且bcac是可能的。

为了防止bcac发生,需要设置一个信号掩码,或者更好的waitpid是,检查返回值,如果它被中断,则再次调用它。

于 2014-08-13T06:38:57.780 回答