问题基础性问题,write是原子化操作吗?

38 views
Skip to first unread message

adream

unread,
Sep 9, 2015, 8:26:10 AM9/9/15
to shlug
举个例子,源程序如下:
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<fcntl.h>
int main()
{
        const char *parent="++++++++\n";
        const char *child="*****************************\n";
        int pid;
        int fd=STDIN_FILENO;
        //int fd=open("/tmp/t.txt",O_WRONLY|O_CREAT);
        //if(fd<0) return -2;
        pid=fork();
        if(pid>0) while(1) write(fd,parent,strlen(parent));
        else if(pid==0) while(1) write(fd,child,strlen(child));
        else return -1;
}
如果write是原子化操作,那么输出应该是类似这样的:
++++++++
*****************************
++++++++
*****************************
不会出现这样的情况
++++*************+++****************+
我实际测试时,似乎也是原子化操作的,但是我没找到可行的文档说明。


Chaos Eternal

unread,
Sep 9, 2015, 8:48:20 AM9/9/15
to sh...@googlegroups.com
write不是原子化操作。

你测不出来是因为并发度不够。
> --
> -- You received this message because you are subscribed to the Google Groups
> Shanghai Linux User Group group. To post to this group, send email to
> sh...@googlegroups.com. To unsubscribe from this group, send email to
> shlug+un...@googlegroups.com. For more options, visit this group at
> https://groups.google.com/d/forum/shlug?hl=zh-CN
> ---
> 您收到此邮件是因为您订阅了Google网上论坛上的“Shanghai Linux User Group”群组。
> 要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到shlug+un...@googlegroups.com
> 要查看更多选项,请访问https://groups.google.com/d/optout

Chaos Eternal

unread,
Sep 9, 2015, 8:51:12 AM9/9/15
to sh...@googlegroups.com
错了,不是并发度不够,而是缺省的cout看到\n才flush。你可以写一个字符flush一次

adream

unread,
Sep 9, 2015, 8:53:59 AM9/9/15
to shlug
我测试的两个字符串parent和child都是\n结尾的,所以写入之后肯定就刷出来了。
写一个字符flush一次就没意义了,我想知道对于一个字符串,write操作是否原子化。

您收到此邮件是因为您订阅了 Google 网上论坛的“Shanghai Linux User Group”群组。

adream

unread,
Sep 9, 2015, 9:09:41 AM9/9/15
to shlug
如果wirte不是原子化操作,那么有什么写文件操作是原子化的?

您收到此邮件是因为您订阅了 Google 网上论坛的“Shanghai Linux User Group”群组。

Xi Shen

unread,
Sep 9, 2015, 9:16:54 AM9/9/15
to shlug
http://linux.die.net/man/3/write

Atomic/non-atomic: A write is atomic if the whole amount written in one operation is not interleaved with data from any other process. This is useful when there are multiple writers sending data to a single reader. Applications need to know how large a write request can be expected to be performed atomically. This maximum is called {PIPE_BUF}. This volume of IEEE Std 1003.1-2001 does not say whether write requests for more than {PIPE_BUF} bytes are atomic, but requires that writes of {PIPE_BUF} or fewer bytes shall be atomic.


Regards,
David

adream

unread,
Sep 9, 2015, 9:39:18 AM9/9/15
to shlug
我看过这个,这里的原子化只真对pipe和FIFO,并没有说对常规文件写操作也是原子化的。
谢谢

Xi Shen

unread,
Sep 9, 2015, 10:15:00 AM9/9/15
to shlug
的确没找到什么地方讨论你的这个问题。一般来说,操作文件都是自己获取独占权限,加锁什么的方法。有什么原因一定要一个系统提供的原子操作吗?

adream

unread,
Sep 9, 2015, 10:25:14 AM9/9/15
to shlug
是这样的,最近在读前人留下来的源代码,我发现他写日志操作最后是调用write函数实现的,没有加锁。
但是写日志操作是被多个进程调用的,长期运行也没发现出现乱码。
所以才有这个疑问。

adream

unread,
Sep 9, 2015, 10:51:58 AM9/9/15
to shlug
我做了一个更为严格的测试:
//write_test.c
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<fcntl.h>
int main()
{
        const char *parent="&&&&&&&&&&&&&\n";
        const char *child="@@@@@@@@@@@@@@@@@@@@@@@\n";
        int pid;
        int fd=STDOUT_FILENO;

        pid=fork();
        if(pid>0) while(1) write(fd,parent,strlen(parent));
        else if(pid==0) while(1) write(fd,child,strlen(child));
        else return -1;
}
gcc write_test.c -o w
./w | grep -v -E "(^&&&&&&&&&&&&&$)|(^@@@@@@@@@@@@@@@@@@@@@@@$)"
如果有乱码,那么grep命令就可以显示输出,但是运行近1小时,未显示任何输出

在 2015年9月9日 下午10:14,Xi Shen <david...@gmail.com>写道:

adream

unread,
Sep 9, 2015, 12:06:00 PM9/9/15
to shlug
我最后用这个程序测试的
//write_test.c
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
int main(const int argc,const char* argv[])
{
    int len=atoi(argv[1])+1;
    char *parent=malloc(len);
    char *child=malloc(len);
    int pid;
    memset(parent,'&',len);
    memset(child,'@',len);
    parent[len-1]=child[len-1]='\n';
    pid=fork(); 
    if(pid>0) while(1) write(STDOUT_FILENO,parent,strlen(parent));
    else if(pid==0) while(1) write(STDOUT_FILENO,child,strlen(child));
    else return -1;
}
gcc write_test.c -o w
./w 100000 | grep -v -E "[&@]{100000}"
这时grep命令有输出了,证明write确实不是原子化的

DaboD

unread,
Sep 9, 2015, 12:18:33 PM9/9/15
to Shanghai Linux User Group
視你的目標平台 & write 標的而定, 也就是說, 不具可攜性...

可參考這篇

如果是 local file 的操作, 也許可參考看看 sqlite 的做法.

DaboD

unread,
Sep 9, 2015, 12:21:59 PM9/9/15
to Shanghai Linux User Group
我看过这个,这里的原子化只真对pipe和FIFO,并没有说对常规文件写操作也是原子化的。
谢谢

如果wirte不是原子化操作,那么有什么写文件操作是原子化的?

> 要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到shlug+unsubscribe@googlegroups.com

> 要查看更多选项,请访问https://groups.google.com/d/optout

--
-- You received this message because you are subscribed to the Google Groups Shanghai Linux User Group group. To post to this group, send email to sh...@googlegroups.com. To unsubscribe from this group, send email to shlug+un...@googlegroups.com. For more options, visit this group at https://groups.google.com/d/forum/shlug?hl=zh-CN
---
您收到此邮件是因为您订阅了 Google 网上论坛的“Shanghai Linux User Group”群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到shlug+unsubscribe@googlegroups.com
要查看更多选项,请访问 https://groups.google.com/d/optout

--
-- You received this message because you are subscribed to the Google Groups Shanghai Linux User Group group. To post to this group, send email to sh...@googlegroups.com. To unsubscribe from this group, send email to shlug+un...@googlegroups.com. For more options, visit this group at https://groups.google.com/d/forum/shlug?hl=zh-CN
---
您收到此邮件是因为您订阅了Google网上论坛上的“Shanghai Linux User Group”群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到shlug+unsubscribe@googlegroups.com
要查看更多选项,请访问https://groups.google.com/d/optout
--

Regards,
David

--
-- You received this message because you are subscribed to the Google Groups Shanghai Linux User Group group. To post to this group, send email to sh...@googlegroups.com. To unsubscribe from this group, send email to shlug+un...@googlegroups.com. For more options, visit this group at https://groups.google.com/d/forum/shlug?hl=zh-CN
---
您收到此邮件是因为您订阅了Google网上论坛上的“Shanghai Linux User Group”群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到shlug+unsubscribe@googlegroups.com
要查看更多选项,请访问https://groups.google.com/d/optout

--
-- You received this message because you are subscribed to the Google Groups Shanghai Linux User Group group. To post to this group, send email to sh...@googlegroups.com. To unsubscribe from this group, send email to shlug+un...@googlegroups.com. For more options, visit this group at https://groups.google.com/d/forum/shlug?hl=zh-CN
---
您收到此邮件是因为您订阅了Google网上论坛上的“Shanghai Linux User Group”群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到shlug+unsubscribe@googlegroups.com
要查看更多选项,请访问https://groups.google.com/d/optout
--

Regards,
David

--
-- You received this message because you are subscribed to the Google Groups Shanghai Linux User Group group. To post to this group, send email to sh...@googlegroups.com. To unsubscribe from this group, send email to shlug+un...@googlegroups.com. For more options, visit this group at https://groups.google.com/d/forum/shlug?hl=zh-CN
---
您收到此邮件是因为您订阅了Google网上论坛上的“Shanghai Linux User Group”群组。
要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到shlug+unsubscribe@googlegroups.com
要查看更多选项,请访问https://groups.google.com/d/optout

lijie

unread,
Sep 9, 2015, 7:19:28 PM9/9/15
to sh...@googlegroups.com
你的字符串不够长,你的例子里只要把字符串加到10K就能出现了。

http://pubs.opengroup.org/onlinepubs/007904975/functions/write.html

按这里的说法,pipe的情况下一次write大于PIPE_BUF就**可能**出现。如果用append方式打开,写操作是原子的,写日志一般用这种方法打开。我测试每次写几MB一行,用append的话没有一条混合,如果没有append,30%以上的行都出现了混合。

Xi Shen

unread,
Sep 9, 2015, 8:21:47 PM9/9/15
to sh...@googlegroups.com
write当然不是原子化的。你在write的时候,也是可能发生线程切换的啊。至于以前的代码直接用write,又没有出现问题,很可能是使用场景的特例。

Regards,
David

Shell Xu

unread,
Sep 9, 2015, 10:47:00 PM9/9/15
to shlug
我简单看了一下内核源码,linux-3.14版的。
简单来说,write的实现会视各种文件系统而不同,不过大体来说,都是同步的,但是没有排它的假定。
彼節者有間,而刀刃者無厚;以無厚入有間,恢恢乎其於游刃必有餘地矣。
blog: http://shell909090.org/blog/

Ray Song

unread,
Sep 11, 2015, 7:25:40 AM9/11/15
to sh...@googlegroups.com
小结一下

和描述符对应的类型相关,

- 对于 pipe 或 FIFO (man 3p write)

* Write requests of {PIPE_BUF} bytes or less shall not be interleaved with data from other processes doing writes on the
same pipe. Writes of greater than {PIPE_BUF} bytes may have data interleaved, on arbitrary boundaries, with writes by
other processes, whether or not the O_NONBLOCK flag of the file status flags is set.

- 文件系统可能都有不同处理,但倾向于认为多数情况 non-atomic

https://lwn.net/Articles/552095/

日志可能会用 O_APPEND 打开(man 2 open `O_APPEND`),此时只能保障 seek 和 write的发起 是原子的,write 内容不是 ( http://www.notthewizard.com/2014/06/17/are-files-appends-really-atomic/ )

On 2015-09-10, Xi Shen wrote:
>write当然不是原子化的。你在write的时候,也是可能发生线程切换的啊。至于以前的代
> >>>> --
> >>>>
> >>>> Regards,
> >>>> David
> >>>>
> >>>> --
> >>>> -- You received this message because you are subscribed to the Google
> >>>> Groups Shanghai Linux User Group group. To post to this group, send
> email to
> >>>> sh...@googlegroups.com. To unsubscribe from this group, send email to
> >>>> shlug+un...@googlegroups.com. For more options, visit this group
> at
> >>>> https://groups.google.com/d/forum/shlug?hl=zh-CN
> >>>> ---
> >>>> 您收到此邮件是因为您订阅了Google网上论坛上的“Shanghai Linux User
> Group”群组。
> >>>> 要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到
> shlug+un...@googlegroups.com
> >>>> 要查看更多选项,请访问https://groups.google.com/d/optout
> >>>
> >>> --
> >>> -- You received this message because you are subscribed to the Google
> >>> Groups Shanghai Linux User Group group. To post to this group, send
> email to
> >>> sh...@googlegroups.com. To unsubscribe from this group, send email to
> >>> shlug+un...@googlegroups.com. For more options, visit this group
> at
> >>> https://groups.google.com/d/forum/shlug?hl=zh-CN
> >>> ---
> >>> 您收到此邮件是因为您订阅了Google网上论坛上的“Shanghai Linux User Group”
> 群组。
> >>> 要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到
> shlug+un...@googlegroups.com
> >>> 要查看更多选项,请访问https://groups.google.com/d/optout
> >>
> >> --
> >>
> >> Regards,
> >> David
> >>
> >> --
> >> -- You received this message because you are subscribed to the Google
> >> Groups Shanghai Linux User Group group. To post to this group, send
> email to
> >> sh...@googlegroups.com. To unsubscribe from this group, send email to
> >> shlug+un...@googlegroups.com. For more options, visit this group
> at
> >> https://groups.google.com/d/forum/shlug?hl=zh-CN
> >> ---
> >> 您收到此邮件是因为您订阅了Google网上论坛上的“Shanghai Linux User Group”
> 群组。
> >> 要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到
> shlug+un...@googlegroups.com
> >> 要查看更多选项,请访问https://groups.google.com/d/optout
> >
> > --
> > -- You received this message because you are subscribed to the Google
> Groups
> > Shanghai Linux User Group group. To post to this group, send email to
> > sh...@googlegroups.com. To unsubscribe from this group, send email to
> > shlug+un...@googlegroups.com. For more options, visit this group at
> > https://groups.google.com/d/forum/shlug?hl=zh-CN
> > ---
> > 您收到此邮件是因为您订阅了Google网上论坛上的“Shanghai Linux User Group”群
> 组。
> > 要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到
> shlug+un...@googlegroups.com
> > 要查看更多选项,请访问https://groups.google.com/d/optout
>
> --
> -- You received this message because you are subscribed to the Google
> Groups Shanghai Linux User Group group. To post to this group, send email
> to sh...@googlegroups.com. To unsubscribe from this group, send email to
> shlug+un...@googlegroups.com. For more options, visit this group at
> https://groups.google.com/d/forum/shlug?hl=zh-CN
> ---
> 您收到此邮件是因为您订阅了 Google 网上论坛的“Shanghai Linux User Group”群组
> 。
> 要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到
> shlug+un...@googlegroups.com
> 要查看更多选项,请访问 https://groups.google.com/d/optout
>
>--
>
>Regards,
>David
>
>--
>-- You received this message because you are subscribed to the Google Groups
>Shanghai Linux User Group group. To post to this group, send email to
>sh...@googlegroups.com. To unsubscribe from this group, send email to
>shlug+un...@googlegroups.com. For more options, visit this group at
>https://groups.google.com/d/forum/shlug?hl=zh-CN
>---
>您收到此邮件是因为您订阅了Google网上论坛上的“Shanghai Linux User Group”群组。
>要退订此群组并停止接收此群组的电子邮件,请发送电子邮件到
>shlug+un...@googlegroups.com
>要查看更多选项,请访问https://groups.google.com/d/optout

--
Ray
http://maskray.me

李扬

unread,
Sep 11, 2015, 11:58:11 PM9/11/15
to Shanghai Linux User Group
建议找个负载重的系统再测试下,尤其文件IO量大的。


在 2015年9月9日星期三 UTC+8下午8:26:10,Adream写道:

adream

unread,
Sep 12, 2015, 7:46:38 PM9/12/15
to shlug
很好奇,你看的是哪个文件,如何确定大体上的同步,既然同步,又怎么说没有排它。
我觉得对程序来说不应该是如此模糊的表示啊。
举个例子说吧,对于ext4文件系统,内核里怎么实现write的,是不是当写入量小于一个特定值时是同步的,否则无法保证同步?
谢谢

Heiher

unread,
Sep 12, 2015, 7:58:02 PM9/12/15
to shlug

我一直是这么理解的,尝试一次write调用指定长度的数据,实际完成后可能等于或小于希望长度,这取决于空闲缓冲区长度。而write返回的长度的数据序列是确定的。也就是说在没有其它高层次的锁保护的情况下,多个writer也只会在每次write的返回长度边界上乱序。不知道理解的对不对。

Cui Yuan

unread,
Sep 14, 2015, 9:09:28 AM9/14/15
to sh...@googlegroups.com

> 在 2015年9月9日,下午8:51,Chaos Eternal <chaose...@shlug.org> 写道:
>
> 您收到此邮件是因为您订阅了 Google 网上论坛的“Shanghai Linux User Group”群组。
Reply all
Reply to author
Forward
0 new messages