微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

父母和孩子在分叉之后是否共享相同的文件偏移量?

在APUE第8.3节的fork function ,关于父进程和subprocess之间的文件共享,

它说: It is important that the parent and the child share the same file offset.

在第8.9节“ Race Conditions ,有一个例子:父母和孩子都写信

一个调用fork函数之前打开的文件。 该scheme包含一个竞赛条件,

因为输出取决于内核运行进程的顺序以及每个进程运行的时间。

但在我的testing代码中,输出是重叠的。

[Langzi @ Freedom apue] $猫race.out

这是一个很长的输出,这是来自父母的长期输出

将dynamic分配的内存返回到操作系统而不终止程序

如何编写一个应用程序,用RFID标签解锁窗口

如何避免从工作线程到GUI线程的主要传播

strcat添加第二个参数两次

如何在文件夹中安装虚拟文件系统?

似乎父母和孩子有单独的文件偏移,而不是共享相同的偏移量。

我的代码中是否有错误? 还是我误解了共享抵消的含义?

任何意见和帮助将不胜感激。

以下是我的代码

#include "apue.h" #include <fcntl.h> void ch@R_404_6460@tatime(int fd,char *); int main() { pid_t pid; int fd; if ((fd = open("race.out",(O_WRONLY | O_CREAT | O_Trunc),S_IRUSR | S_IWUSR)) < 0) err_sys("open error"); if ((pid = fork()) < 0) err_sys("fork error"); else if (pid == 0) ch@R_404_6460@tatime(fd,"this is a long long output from childn"); else ch@R_404_6460@tatime(fd,"this is a long long output from parentn"); exit(0); } void ch@R_404_6460@tatime(int fd,char *str) { // try to make the two processes switch as often as possible // to demonstrate the race condition. // set synchronous flag for fd set_fl(fd,O_SYNC); while (*str) { write(fd,str++,1); // make sure the data is write to disk fdatasync(fd); } }

linux内核源代码中__section()是什么意思?

设置没有System.Windows.Forms的鼠标位置

为什么我的信号处理程序(抛出exception)不止触发一次?

无法识别的音乐格式使用SDL播放mp3文件

c + + win32阻止应用程序在Windows XP上运行

那么,我错了。

所以,他们正在分享抵消,但其他奇怪的事情正在发生。 如果他们没有分享一个抵消,你会得到这样的输出

this is a long long output from chredt

因为每个人都会开始写自己的偏移0,并且一次推进一个角色。 他们不会开始冲突写什么文件,直到到达句子的最后一个单词为止,这将最终交错。

所以,他们分享一个抵消。

但奇怪的是,它似乎并没有得到原子更新的偏移,因为没有进程输出完整。 这就像一个人的某些部分覆盖了另一个部分,即使他们也提前的抵消,总是不会发生。

如果偏移量没有被共享,那么文件中的字节数最多只能是两个字符串中最长的一个

如果偏移量是以原子方式共享和更新的,则两个字符串放在一起会导致文件中的字节数完全相同。

但是,最终在文件中的某个字节之间会有一些字节,这意味着这些字段是共享的,而不是自动更新的,这很简单。 但是,这显然是发生了什么事情。 多么奇怪。

进程A将偏移量读入A.offset

过程B将偏移量读入B.offset

进程A在A.offset处写入字节

过程A设置offset = A.offset + 1

进程B在B.offset处写入字节

进程A将偏移量读入A.offset

过程B设置偏移量= B.offset + 1

进程A在A.offset处写入字节

过程A设置offset = A.offset + 1

过程B将偏移量读入B.offset

进程B在B.offset处写入字节

过程B设置偏移量= B.offset + 1

这大概是事件的顺序必须是什么。 多么奇怪。

存在pread和pwrite系统调用,所以两个进程可以在特定位置更新文件,而不用争夺全局偏移值的胜利。

父和子在内核中共享相同的文件表项,其中包括偏移量。 那么父母和孩子不可能有一个或两个关闭和重新打开文件的过程。 所以,父母的任何写入使用此偏移量并修改(增量)偏移量。 然后,任何由孩子写入使用新的偏移量,并修改它。 一次写一个字符会加剧这种情况。

从我的写(2)手册页:“调整文件偏移量和写入操作作为原子步骤执行。

所以,从这里可以保证,一个人(父母或小孩)的写作不会超过另一个的写作。 你也可以注意到,如果你要一次性写完(2)整个句子(在一次写作(2)的过程中),保证句子将被一起写入。

实际上,许多系统都是这样写日志文件的。 许多相关的进程(同一父进程的子进程)将有一个由父进程打开的文件描述符。 只要他们每次写一整行(用一次调用write(2)),日志文件就会按你所希望的那样读取。 一次写一个角色不会有同样的保证。 使用输出缓冲(用stdio)会同样的去除保证。

如果我从我的操作系统类正确地记得,分叉确实给孩子它自己的偏移(虽然它开始在父母相同的位置),它只是保持相同的打开文件表。 虽然,我正在阅读的大部分内容似乎另有说明。

那么,我调整了代码,在香草GCC / glibc编译,这里是一个示例输出

thhis isias al long oulout futput frd parent

我认为这支持文件的位置是共享的,这是一个竞争,这就是为什么它是如此奇怪的想法。 注意我显示的数据有47个字符。 这比单个消息的38或39个字符更多,并且两个消息的77个字符都少于77个字符 – 我可以看到发生这种情况的唯一方式是,如果进程有时竞相更新文件位置 – 它们每个都写一个字符,他们每个人都试图增加位置,但由于种族只发生了一个增量,一些字符被覆盖。

支持证据:我的系统上的man 2 lseek清楚地说

请注意,由dup(2)或fork(2)创建的文件描述符共享当前文件位置指针,因此查找这样的文件可能会受到竞争条件的影响。

使用pwrite自写有时结束竞争条件当相同的资源(写())由多个进程共享,因为写完成后没有离开文件pos = 0例如你最终在文件的中间所以文件指针(fd)指向这个位置,如果其他进程想要做一些事情,那么它产生或工作不像它想做的那样,因为文件描述符将在分叉之间共享!

尝试并给我反馈

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐