多个进程操作同一个文件的问题

2640阅读 1评论2014-06-05 zealoussnow
分类:LINUX

        今天一同事问我,有多个进程同时操作一个文件时会发生什么情况。我的回答是系统不管你怎么搞,反正同一时刻只有一个进程操作文件,这个回答似乎有点笼统,连自己也说服不了,为此专门查了下APUE,顺便百度了一下(坑爹的公司上不了google啊),总结如下:

一、多个进程以只写模式打开文件
  1. #include <errno.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>

  5. #include <sys/file.h>
  6. #include <sys/types.h>
  7. #include <sys/stat.h>
  8. #include <fcntl.h>

  9. int main(int argc, char *argv[])
  10. {
  11.     int fd = open("demo.txt", O_WRONLY, 0644);
  12.     if (fd < 0)
  13.     {
  14.         perror("Open file error");
  15.         exit(EXIT_FAILURE);
  16.     }
  17.     write(fd, "Hello", 5);
  18.     sleep(30);

  19.     return 0;
  20. }
        当一个进程将Hello写入文件时,如果再启另一个进程来操作文件,实际最终写入文件的只有一个Hello。这里跟多个进程操作一个文件没多大关系,最主要的原因还是打开文件的方式,manpage上解释道;如果一个文件已经存在且是一个普通文件,当设置的打开模式允许写时,会将文件截断。也就是说无论是否是多个进程在操作同一个文件,打开的模式设置为可以只读的,那么只有最后操作文件的那个进程的写操作生效。

二、以追加模式打开文件

  1. #include <sys/stat.h>
  2. #include <fcntl.h>

  3. int main(int argc, char *argv[])
  4. {
  5.     int fd = open("demo.txt", O_WRONLY | O_APPEND, 0644);
  6.     if (fd < 0)
  7.     {
  8.         perror("Open file error");
  9.         exit(EXIT_FAILURE);
  10.     }
  11.     write(fd, "Hello", 5);
  12.     sleep(30);
  13.     
  14.     return 0;
  15. }
        此时每次写都将数据写到文件的当前尾端。现在如果有多个进程操作一个文件,那么来自每个进程的数据都将正确地写到文件中。关于linux如何保证多个进程写入数据时的正确性的,可以参考APUE的文件爱你共享和原子操作这两节。

三、为了防止在多进程环境中对同一文件的写操作出现问题,可以对文件加锁,保证这个资源在某一时刻只能被一个进程操作。加锁文件时,如果需要加锁整个文件,可以选用flock,而用fcntl的话,可以对文件的一部分加锁,下面以fcntl函数说明下:

  1. #include <errno.h>
  2. #include <fcntl.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>

  5. #include <unistd.h>

  6. #define DEMO_FILE "./demo"

  7. /* Function to lock or unlock a region of a file */
  8. int lock_reg(int fd, int cmd, int type, off_t offset, int whence, off_t len)
  9. {
  10.     struct flock lock;

  11.     lock.l_type = type; /* F_RDLCK, F_WRLCK, F_UNLCK */
  12.     lock.l_start = offset; /* byte offset, relative to l_whence */
  13.     lock.l_whence = whence; /* SEEK_SET, SEEK_CUR, SEEK_END */
  14.     lock.l_len = len; /* #bytes (0 means to EOF) */

  15.     return(fcntl(fd, cmd, &lock));
  16. }

  17. int main(int argc, char *argv[])
  18. {
  19.     int fd = open(DEMO_FILE, O_RDWR);
  20.     if (fd == -1)
  21.     {
  22.         perror("Can not open the specified file");
  23.         exit(EXIT_FAILURE);
  24.     }
  25.     int ret = lock_reg(fd, F_SETLK, F_WRLCK, 0, 0, 0);
  26.     if (ret == -1)
  27.     {
  28.         printf("Error number is: %d\n", errno);
  29.         perror("Can not lock the file");
  30.         exit(EXIT_FAILURE);
  31.     }
  32.     getchar();

  33.     return 0;
  34. }
        这段代码演示了当一个进程对文件加锁后,则另一个进程就无法获得资源。这种独写性质在很多时候需要用到,如果数据库,以前用的小型的数据库,如sqlite就与这类似。所以,一般情况下,在多进程环境中,要对一些共享的资源进行操作时,要保证操作的原子性,要么使用锁,要么用类似syslog那种把所有写操作统一由一个进程来进行。
        很多时候懒得去想问题,特别实在这个大夏天,整个人都会变得很燥,静下来仔细思考遇到过的问题,认真总结,终有云开雾散的时候......
上一篇:没有了
下一篇:一个简单的磁盘序列号获取类