免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 18566 | 回复: 50
打印 上一主题 下一主题

多个进程把日志记录在同一个文件的问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-08-03 23:43 |只看该作者 |倒序浏览
一个程序有多个进程,父子进程都以O_APPEND方式打开同一个日志文件,用系统调用write向文件写入一条日志,像这种没有进程间相互协调,会不会出现日志信息混乱的情况(一个进程的日志写入一半后出现另一进程的日志)。
写了个小程序测试了一下,很简单的两个进程,大家看看,这个程序没有出现信息混乱的情况。可能因为写入的信息太少,没有发生在日志写到一半的时候出现进程间切换。


  1. #include <unistd.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <sys/stat.h>
  5. #include <sys/types.h>
  6. #include <fcntl.h>

  7. int main(int argc,char * argv[])
  8. {
  9.         int fd;
  10.         int childpid;
  11.         int i;
  12.         char buf[1024];

  13.         for(i=0 ;i<1; i++){
  14.                 if(childpid = fork())
  15.                         break;
  16.         }

  17.         if(childpid == -1){
  18.                 perror("failed to fork\n");
  19.                 return 1;
  20.         }

  21.         fd = open("tmp.dat",O_WRONLY|O_CREAT|O_APPEND,0666);
  22.         if(fd < 0){
  23.                 perror("failed to open\n");
  24.                 return 1;
  25.         }
  26.         if(childpid > 0){
  27.                 memset(buf,0,1024);
  28.                 strcpy(buf,"1111111111111111111111111111111111111111111111111111111111111111111111111111111111
  29. 1111111111111111111111111111111111111111111111111111111");
  30.                 strcat(buf,"\n");
  31.                 for(i=0; i<100000; i++){
  32.                         usleep(1000);
  33.                         write(fd,buf,strlen(buf));
  34.                 }
  35.         }else{
  36.                 memset(buf,0,1024);
  37.                    strcpy(buf,"2222222222222222222222222222222222222222222222222222222222222222222222222222222222
  38. 222222222222222222222222222222222222222222222222222222");
  39.                 strcat(buf,"\n");
  40.                 for(i=0; i<100000; i++){
  41.                         usleep(1000);
  42.                         write(fd,buf,strlen(buf));
  43.                 }

  44.         }

  45.         close(fd);
  46.         return 0;
  47. }

复制代码

[ 本帖最后由 linuxiang 于 2006-8-3 23:46 编辑 ]

论坛徽章:
0
2 [报告]
发表于 2006-08-04 01:09 |只看该作者
write 并非原子操作,当然会出现交叉的情况

论坛徽章:
0
3 [报告]
发表于 2006-08-04 02:19 |只看该作者
不会,read和write是系统调用,是原子操作。放心用吧。如果用fread和fwrite就要小心了,因为glibc有一个进程内的buffer,会造成数据不完整。

论坛徽章:
0
4 [报告]
发表于 2006-08-04 08:19 |只看该作者
偶单位有个系统开始也是这种方式,append打开写,关闭。说io太高,后来改成写消息队列,单独一个进程循环读队列写日志文件。io确实小了很多。

论坛徽章:
0
5 [报告]
发表于 2006-08-04 08:32 |只看该作者
不会。

read, write 可以认为是原子的。中间不会被打断。写LOG是APPEND,无数进程不会乱。
当如果你自己写LOG,必须一个记录一个write调用写入。如果2次以上write调用一个记录就会交错。

论坛徽章:
0
6 [报告]
发表于 2006-08-04 09:32 |只看该作者
原帖由 思一克 于 2006-8-4 08:32 发表
不会。

read, write 可以认为是原子的。中间不会被打断。写LOG是APPEND,无数进程不会乱。
当如果你自己写LOG,必须一个记录一个write调用写入。如果2次以上write调用一个记录就会交错。

老大,如果日志是在nfs或是磁带上,还能认为是原子的吗?一个程序,总不能挑文件系统吧?

论坛徽章:
0
7 [报告]
发表于 2006-08-04 09:39 |只看该作者
还是用守护进程+消息队列的方式比较理想,可以充分利用缓存减少 IO。


PS: 我一直比较欣赏微内核+消息传递的操作系统

论坛徽章:
0
8 [报告]
发表于 2006-08-04 09:48 |只看该作者
你说的到可以考虑。

有一点,read write 是原子的,对于磁盘,pipe, sock等都是。许多著名的程序都是基于这一点。
比如qmail系统,它100个进程用write写一个pipe发命令,如果某个write会被其他write打断,那系统就崩溃。

不会“被其它write打断”。
至于被别的事件是可能打断的,但这不妨碍write的原子性,因为没有被其他write打断,数据不会交错。

至于TAPE上,TAPE是顺序设备,更应该没有问题。
NFS,你能证明有问题吗。我不肯定是否。


原帖由 isnowran 于 2006-8-4 09:32 发表

老大,如果日志是在nfs或是磁带上,还能认为是原子的吗?一个程序,总不能挑文件系统吧?

论坛徽章:
0
9 [报告]
发表于 2006-08-04 09:59 |只看该作者
?我记忆中原子操作只有sync,open,fcntl,dup以及锁等等为数不多的函数,从来没有印象书中说过write、read也是原子操作,我先去查查。。。

论坛徽章:
0
10 [报告]
发表于 2006-08-04 10:08 |只看该作者
to isnowran,

那你的印象可能不对。

系统调用对于系统调用应该是“原子”的。例如100个P 同时write 一个文件,当P1 正在KERNEL中write时,P2的write一定不可能打断在KERNEL中的P1。如果理解KERNEL的调度,进程切换的方式和时机,对理解这个有帮助。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP