今天一同事问我,有多个进程同时操作一个文件时会发生什么情况。我的回答是系统不管你怎么搞,反正同一时刻只有一个进程操作文件,这个回答似乎有点笼统,连自己也说服不了,为此专门查了下APUE,顺便百度了一下(坑爹的公司上不了google啊),总结如下:
一、多个进程以只写模式打开文件
-
#include <errno.h>
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <unistd.h>
-
-
#include <sys/file.h>
-
#include <sys/types.h>
-
#include <sys/stat.h>
-
#include <fcntl.h>
-
-
int main(int argc, char *argv[])
-
{
-
int fd = open("demo.txt", O_WRONLY, 0644);
-
if (fd < 0)
-
{
-
perror("Open file error");
-
exit(EXIT_FAILURE);
-
}
-
write(fd, "Hello", 5);
-
sleep(30);
-
-
return 0;
-
}
当一个进程将Hello写入文件时,如果再启另一个进程来操作文件,实际最终写入文件的只有一个Hello。这里跟多个进程操作一个文件没多大关系,最主要的原因还是打开文件的方式,manpage上解释道;如果一个文件已经存在且是一个普通文件,当设置的打开模式允许写时,会将文件截断。也就是说无论是否是多个进程在操作同一个文件,打开的模式设置为可以只读的,那么只有最后操作文件的那个进程的写操作生效。
二、以追加模式打开文件
-
#include <sys/stat.h>
-
#include <fcntl.h>
-
-
int main(int argc, char *argv[])
-
{
-
int fd = open("demo.txt", O_WRONLY | O_APPEND, 0644);
-
if (fd < 0)
-
{
-
perror("Open file error");
-
exit(EXIT_FAILURE);
-
}
-
write(fd, "Hello", 5);
-
sleep(30);
-
-
return 0;
-
}
此时每次写都将数据写到文件的当前尾端。现在如果有多个进程操作一个文件,那么来自每个进程的数据都将正确地写到文件中。关于linux如何保证多个进程写入数据时的正确性的,可以参考APUE的文件爱你共享和原子操作这两节。
三、为了防止在多进程环境中对同一文件的写操作出现问题,可以对文件加锁,保证这个资源在某一时刻只能被一个进程操作。加锁文件时,如果需要加锁整个文件,可以选用flock,而用fcntl的话,可以对文件的一部分加锁,下面以fcntl函数说明下:
-
#include <errno.h>
-
#include <fcntl.h>
-
#include <stdio.h>
-
#include <stdlib.h>
-
-
#include <unistd.h>
-
-
#define DEMO_FILE "./demo"
-
-
/* Function to lock or unlock a region of a file */
-
int lock_reg(int fd, int cmd, int type, off_t offset, int whence, off_t len)
-
{
-
struct flock lock;
-
-
lock.l_type = type; /* F_RDLCK, F_WRLCK, F_UNLCK */
-
lock.l_start = offset; /* byte offset, relative to l_whence */
-
lock.l_whence = whence; /* SEEK_SET, SEEK_CUR, SEEK_END */
-
lock.l_len = len; /* #bytes (0 means to EOF) */
-
-
return(fcntl(fd, cmd, &lock));
-
}
-
-
int main(int argc, char *argv[])
-
{
-
int fd = open(DEMO_FILE, O_RDWR);
-
if (fd == -1)
-
{
-
perror("Can not open the specified file");
-
exit(EXIT_FAILURE);
-
}
-
int ret = lock_reg(fd, F_SETLK, F_WRLCK, 0, 0, 0);
-
if (ret == -1)
-
{
-
printf("Error number is: %d\n", errno);
-
perror("Can not lock the file");
-
exit(EXIT_FAILURE);
-
}
-
getchar();
-
-
return 0;
-
}
这段代码演示了当一个进程对文件加锁后,则另一个进程就无法获得资源。这种独写性质在很多时候需要用到,如果数据库,以前用的小型的数据库,如sqlite就与这类似。所以,一般情况下,在多进程环境中,要对一些共享的资源进行操作时,要保证操作的原子性,要么使用锁,要么用类似syslog那种把所有写操作统一由一个进程来进行。
很多时候懒得去想问题,特别实在这个大夏天,整个人都会变得很燥,静下来仔细思考遇到过的问题,认真总结,终有云开雾散的时候......
阅读(2648) | 评论(1) | 转发(0) |