2
#include <fcntl.h>
#include <stdlib.h>
int fdrd,fdwt;
char c;
void rdwrt();
main(int argc,char *argv[])
{
    if(argc!=3)
        exit(1);
    if((fdrd=open(argv[1],O_RDONLY))==-1)
        exit(1);
    if((fdwt=creat(argv[2],0666))==01)
        exit(1);
    fork();
    rdwrt();
    exit(0);
}
void rdwrt()
{
    for(;;)
    {
        if(read(fdrd,&c,1)!=1)
            return;
        write(fdwt,&c,1);
    }
}

该程序分叉一个子进程,然后父进程和子进程尝试读取相同的输入文件并写入相同的输出文件。

像这样执行这个程序:

[root@localhost]./a.out input output

其中输入文件的内容是:

abcdefghijklmnopqrstuvwxyz
abcdefghijklmnopqrstuvwxyz
abcdefghijklmnopqrstuvwxyz
abcdefghijklmnopqrstuvwxyz
abcdefghijklmnopqrstuvwxyz
abcdefghijklmnopqrstuvwxyz

我认为输出文件应该与输入文件具有相同数量的字符,尽管根据这两个进程的竞争,字符顺序可能不一样。

原来输出文件是:

abcdefghijklmnonqbcdefghijklwxyczdefjklpqrstuvwxyz
abcefgklmvwxefgklmnopqrstuvw
qrstuyz
abcdhijxyz

实际上,这两个文件有不同的字符编号

[root@localhost]wc -m input output
162 input
98  output

现在我想知道为什么?

4

1 回答 1

1

输出文件的内容将难以预测,因为您的程序包含竞争条件具体来说,它取决于进程调度。

请求更新:

这个问题实际上比乍一看更有趣。

我要做一些预测(测试成功...)

在类 Unix 系统1 ... 那么,的,字符数将始终相同,但顺序将难以预测。

您标记了您的问题linux unix,并且在这些系统中,所有系统1都正确实现了 fork 模型,两个子项将为 的两个(分叉)实例fdrd共享一个文件位置,并且他们将为fdwr.

如果您可以放慢时间并观看程序运行,那么在任何时候都有您知道和不知道的事情。

您不知道哪个孩子将赢得下一次阅读的比赛,但您确实知道获胜者将阅读哪个字符,因为它们始终位于相同的文件位置。在获胜者获得下一个角色后,您仍然不知道谁会阅读下一个角色,因为比赛仍在进行。

事实上,同一个进程可能会一次又一次地赢得比赛,因为调度程序可能不希望在非常小的时间片内运行它。

在任何时候,您也知道下一个字符将在 EOF 写入,因为再次共享写入位置。

现在,您可能会问,那么,如果两个进程始终处于相同的输入和输出文件位置,那么文件是如何被破解的呢?

好吧,比赛不止一场,一场是阅读,另一场是写作。(或者一个,有点复杂的比赛。)一个孩子可能已经读过它的角色,但在时间切片时没有写出来。所以现在它开始输给写语句,然后可能输给几次读/写迭代。所以一个角色可以挂在一个孩子身上。

最后,在其他操作系统上运行的仅与 API 兼容的 C 环境中,任何事情都可能发生。OP 的系统似乎就是其中之一,或者测试可能存在缺陷。我的 OSX 系统按预期运行。


1. “真正的” UNIX、*BSD、OSX 或 Linux。

于 2013-04-10T13:48:48.677 回答