Linux C/C++多进程同时写一个文件(二)
本文是这《Linux C/C++多进程同时写一个文件》系列文章的第二篇,上一篇文章演示了两个非亲缘关系的进程同时写一个文件的情形,并得出了数据只会错乱但不会覆盖
的结论。这篇文章主要是讨论两个亲缘进程(fork)同时写一个文件的情况。
1 查看要写入的文件的inode信息
使用如下命令可以查看要写入的文件LINUX_MUTIL_PROCESS_WRITE
对应的inode情况,可以看到它的值为67530179
。
[vfhky@typecodes fork2]$ stat /home/vfhky/src/linux/process/fork2/LINUX_MUTIL_PROCESS_WRITE_1
File: ‘/home/vfhky/src/linux/process/fork2/LINUX_MUTIL_PROCESS_WRITE_1’
Size: 671744 Blocks: 1312 IO Block: 4096 regular file
Device: 803h/2051d Inode: 67530179 Links: 1
Access: (0664/-rw-rw-r--) Uid: ( 1000/ vfhky) Gid: ( 1000/ vfhky)
Access: 2017-10-29 15:48:33.404406925 +0800
Modify: 2017-10-28 20:36:34.185587055 +0800
Change: 2017-10-28 20:36:34.185587055 +0800
Birth: -
[vfhky@typecodes fork2]$
2 示例程序
下面这个linux_process_fork2_1.c
程序很简单,主要是fork后的父子进程把对应p_buf指向的静态区数据写入到文件LINUX_MUTIL_PROCESS_WRITE_1
中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
|
3 开始测试
打开一个linux ssh终端,使用ps ux
命令可以看到父进程(pid为6524)和子进程(pid为6525)。
再打开一个ssh终端,使用lsof -p 6524
命令查看两个进程打开的文件情况,从下图中可以看出这两个进程开打的都是同一个文件(对应的inode值为67530179)。
使用ll /proc/6524/fd
命令查看两个进程表项中的所有文件描述符,都是标准输入0
、标准输出1
、标准错误输出2
和打开的文件对应的描述符3
。也就是说对于文件描述符3
来说,这两个进程表项指向的文件表项中的v节点指针指向的是同一个v节点(包含i节点、文件长度等信息,且唯一)。
使用strace -p 6524
命令查看两个进程的内核调用情况,可以看到这两个进程由于for循环的缘故,一直在调用usleep
和fwrite
函数,而这两个函数最终会调用内核的nanosleep
和write
函数。
需要思考一点,为什么会函数write(3, "34567891234567891234567891234567"..., 4096) = 4096
第2个参数不是程序中指定的abcdefghi
而是4096个字节的字符。从这里可以延伸到write
和fwrite
的区别,就不多说了。
最后通过tail -f LINUX_MUTIL_PROCESS_WRITE
命令查看文件写入情况,从下图两个红色标注可以看出父进程写入4096字节(123456789
)后在字符3
后子进程开始4096字节(abcdefghi
)。
4 结论
从上面小节的测试过程可以发现,和上文中两个非亲缘关系的进程同时写一个文件一样,两个亲缘关系的父子进程同时写一个文件时会出现数据混乱的情况,但是两个进程写入的数据没有覆盖。
由于父子进程表项中fd=3指向同一个文件表项,因此两个进程对应文件表项中当前文件偏移量是唯一的,所以尽管在程序没有fopen函数没有使用append
模式保证每次写入时的文件偏移量是正确的,但是依然能做到数据无覆盖。
这点从程序输出结果可以验证,父子进程分别写入了90000字节,所以文件总共大小为180000字节。
Comments »