免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: rain_fish
打印 上一主题 下一主题

关于多线程对同一个文件进行写操作,记得坛子里面讨论过,不需要互斥,原因什么来着? [复制链接]

论坛徽章:
0
51 [报告]
发表于 2010-10-20 14:04 |只看该作者
回复 50# rain_fish


write磁盘文件不具有原子性。
write O_APPEND方式具有原子性。
write socket不具有原子性。
write pipe 在数据尺寸小于一个固定的大小(比如4096,有个参数,我忘记是啥名字了)的时候具有原子性。更大的不原子了。

所以,多线程/进程write同一个磁盘文件需要加锁。而APPEND方式write(日志多是如此)不需要加锁。

论坛徽章:
1
申猴
日期:2014-02-11 14:50:31
52 [报告]
发表于 2010-10-20 14:31 |只看该作者
回复  rain_fish


write磁盘文件不具有原子性。
write O_APPEND方式具有原子性。
write socket不具有 ...
思一克 发表于 2010-10-20 14:04



还是有很多没有搞清楚的(比如:O_APPEND为什么就具有原子性, 休眠和TCP乱套问题等等),看来目前我只能死记硬背了先了

论坛徽章:
0
53 [报告]
发表于 2010-10-20 14:41 |只看该作者
还是有很多没有搞清楚的(比如:O_APPEND为什么就具有原子性, 休眠和TCP乱套问题等等),看来目前我只能死记硬背了先了
-----------------
我猜测的:
因为APPEND方式永远是无重叠写入的。
其实是内部seek机制的原子性导致的。
比如有2个进程竞争write fd, APPEND写之前要seek到文件尾。
当前文件尾是S;
A: write(fd, buf, 1000);
B: write(fd, buf1, 200);
内部A就要写入位置S--->S+1000
B就要写入S+1000 ---> S + 1200

1000个字节write 完成之前,S值已经是S+1000了。

论坛徽章:
1
申猴
日期:2014-02-11 14:50:31
54 [报告]
发表于 2010-10-20 15:01 |只看该作者
还是有很多没有搞清楚的(比如:O_APPEND为什么就具有原子性, 休眠和TCP乱套问题等等),看来目前我只能死记硬 ...
思一克 发表于 2010-10-20 14:41



    恩。虽然没找到对应的源码,但有道理!

论坛徽章:
0
55 [报告]
发表于 2010-10-20 16:56 |只看该作者
回复  rain_fish


write磁盘文件不具有原子性。
write O_APPEND方式具有原子性。
write socket不具有 ...
思一克 发表于 2010-10-20 14:04



    非常感谢,如果是fopen就是fopen("path", 'a')的打开方式是原子的,对吧

论坛徽章:
0
56 [报告]
发表于 2010-10-21 10:32 |只看该作者
本帖最后由 epegasus 于 2010-10-21 10:39 编辑

回复 51# 思一克


    25楼的作废。

对这个问题可讨论的是
1,相关标准给出了什么,比如POSIX
2,具体操作系统实现给出了什么,主要针对但不限于linux。

首先看中文APUE第3章相关描述write:
其返回值通常与参数nbytes的值不同,否则表示出错。
如果在打开该文件时,指定了
O_APPEND选择项,则在每次写操作之前,将文件位移量设置在文件的当前结尾处。在一次成功写之后,该文件位移量增加实际写的字节数。

可以理解为write只有成功和失败2种,成功只有一种返回值,其他都是失败的。
最后一句应该是说写成功后才去增加文件偏移,没成功估计是不增加了。这个问题的关键是没有成功时文件长度是否变化了。按道理说应该没变化。
并且知道O_APPEND而设置文件偏移是在本次写前做出的。增加文件长度应该在写成功后做出的,或许同时也增加了一次偏移。如此大概是2步。
在讲原子的,首先区分以下2个原子:
1,O_APPEND写第一步和第2步中间不被打断。
2,第2步写本身不被打断。
对于2,这有几种保护方式:
写本身是互斥;
写一个有重叠区间是互斥的;
将区间分固定页块,写同一个页块是互斥的。
如果是第一种则O_APPEND写的2步是真正原子的。
试想2个进程同时写,如果不是第一种,则后写的进程面临的问题是哪里才是文件的结尾?因为先写的并没有完成。这个时候要么等写完。要么使用未增加的文件结尾。问题就是一个正在被写的文件结尾是否有效果。
对于非真正原子情况的考虑,这里还有个写失败的问题。就不谈了。
如果按以上描述,一个write真正的写部分是不能被另一个打断的。
比如一个写aaaa 一个写bbbb结果可能是aabbbb 但不可能是abab。
而追加方式下一定是aaaabbbb)(假设2个都是O_APPEND方式打开)


具体看linux实现
2.4   2.6.13中的ext2(ext3不是)都是如此
对一个普通文件的写实际被
sys_write()->
generic_file_write()->down(&inode->i_sem)互斥
所以结论还是write数据过程本身是原子的,对同一个inode的操作不会产生交错。符合以上APUE的定义。

2.6.21中ext2的write改为do_sync_write
也是在generic_file_aio_write里mutex_lock(&inode->i_mutex)保护,仍然符合

论坛徽章:
0
57 [报告]
发表于 2010-10-21 10:53 |只看该作者
回复 56# epegasus


O_APPEND的原子性估计和2个因素有关,
1)文件系统。好像说NFS(还有NTFS?)不行。而linux下的EXT2,3都可以
2)写的块的大小。一页内的应该可以(?)。这个我没有确定。

我的应用写LOG都是用不加锁的,LOG行长肯定是小于4096的。完全没有交错问题。从来没有。

普通的write系统调用中间是要被打断的。也就是其实不一定是一次写完的内容。如果写的位置重叠就有可能交错。
aaaabbbb变成aaabbbba类似的。

我没有测试过O_APPEND写的块大小超过4096的情况如何。

论坛徽章:
0
58 [报告]
发表于 2010-10-21 11:11 |只看该作者
回复 57# 思一克


    我所说的不能交错是指2个进程各只执行一次write.
测试的交错是由于执行多次看到的结果
区别是:如果一次write下不能交错,则不会发生前面提到的追加方式写失败时出现文件空洞.

论坛徽章:
1
申猴
日期:2014-02-11 14:50:31
59 [报告]
发表于 2010-10-21 11:32 |只看该作者
还是比较赞同思一克兄的观点。

to epegasus

可以不用看具体文件系统的实现,我觉得只看到vfs那层就行了

论坛徽章:
0
60 [报告]
发表于 2010-10-21 11:54 |只看该作者
回复 57# 思一克


    我所说的不能交错是指2个进程各只执行一次write.
测试的交错是由于执行多次看到的结果
区别是:如果一次write下不能交错,则不会发生前面提到的追加方式写失败时出现文件空洞.
--------------------------
各执行一次也可能将aaaaaaaaaaabbbbbbbbbbbbb搞成aaaaaabbaaaaaaabbbbbbbbb样子。
只要数据块足够长就可能发生。

一般应用比如写LOG都是执行很多次,不断地执行。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP