Linux应用开发--原子操作

对于操作一个文件,我们想在文件末尾追加一些内容,如果是单个进程的话那么能没有任何问题的完成任务,但如果多个进程都想给文件追加内容的话那就容易出问题了,出现什么问题呢?就是最后的操作结果根本就不是你能接受的了的。

假定两个进程A和B都对同一个文件进行追加内容操作。两个进程都已经打开了该文件,但未使用O_APPEND标志。因此每个进程都有它自己的文件表项,他们有各自的文件状态标志和当前文件偏移,但是他们共享v节点指针。假如进程A调用了定位文件指针函数lseek,它在文件尾端设置偏移500个字节。然后内核切换了进程运行,进程B将文件尾端偏移也设置为500,然后B调用write函数使文件偏移增加至600,由于共享v节点指针,将文件长度更新为增加600字节,然后又切换回A运行,A调用write写入内容时会从文件尾端偏移500处开始写入,这样就会将B写入的数据覆盖一部分。

问题出在将文件定位和写操作分成两部分的裸机操作。解决方法是这两个操作对于其他进程是原子操作。(任何要求多于一个函数调用的操作都不会是原子操作,因为在两个函数调用之间可能会出现内核调度的情况导致自身进程挂起)。Unix给我们提供了一种方法,即在打开文件时使用O_APPEND标志,进程对文件偏移量调整和数据追加成为原子操作,这样就不用每次在写操作之前使用lseek定位到文件尾端了。

还有另一种原子操作:对open函数的O_CREAT和O_EXCL的使用,如果该文件存在,open将失败,否则创建该文件,并且让判定文件是否存在的过程和创建文件的过程成为原子操作。

对于加入了O_APPEND标志之后的write的执行过程是这样的:

write()

{

1、从i节点读取文件长度当做偏移量

2、往文件中写入数据

3、修改i节点中的文件长度

}

这样就让write成为一个原子操作,即只有在A进程write完成后才会轮到B进程write,作为一个整体,要么write内的三个操作都完成,要么都会失败

举一个小例子说明;

int main(int argc,char **argv)
{
	int fd;
	fd = open(argv[2],O_WRONLY|O_APPEND);//pathname
	if(fd < 0)
	{
		perror("open error\n");
		exit(1);
	}
	
	sleep(5);
	//往文件追加内容
	size_t size = strlen(argv[1]) * sizeof(char);
	if(write(fd,argv[1],size) != size)//argv[1]为写入的内容
	{
		perror("write error\n");
		exit(1);
	}
	close(fd);
	return 0;
}

在程序中,启动两个进程在同一个文件中进行追加内容操作,睡眠表示能让两个进程及时运行。由于在open文件时使用了O_APPEND标志,所以在写入时不会出现混乱,也可以尝试去掉O_APPEND标志看看现象。

你可能感兴趣的:(linux应用开发)