参考书目:Unix/Linux 系统编程手册 chapter 5
一、原子操作以及竞争条件
原子操作(atomicity):将某一系统调用所要完成的各个动作作为不可中断的操作,一次性加以执行,内核使该系统调用不会为其他进程或线程中断。原子操作规避了竞争状态(race conditions)。操作共享资源的两个进程(或线程),其结果取决于一个无法预期的顺序。
以独占方式创建一个文件
由于需要先判断文件是否存在,再创建文件,所以可能会出现如图问题:
结合O_CREAT和O_EXCL标志来一次性调用open()可以防止出现两个进程均声明自己是文件的创建者的情况。
向文件尾部追加数据
推荐使用O_APPEND标志来防止lseek()和write()时非原子操作可能造成的问题。
对于O_APPEND,练习题5.2
/*************************************************************************
> File Name: test.c
> Author: 0nism
> Mail: 3099456402@qq.com
> Created Time: Thu 06 Sep 2018 07:24:50 PM CST
************************************************************************/
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
int main(int argc, char * argv[])
{
int fd;
ssize_t numWrite;
off_t offset;
// 检测文件是否存在
fd = open(argv[1], O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
if (fd == -1 && errno == EEXIST)
{
printf("File exist! OK.\n");
}
else
{
printf("File didn't exist.\n");
exit(EXIT_FAILURE);
}
fd = open(argv[1], O_WRONLY | O_APPEND);
if (fd == -1)
{
perror("open");
exit(EXIT_FAILURE);
}
offset = lseek(fd, 0, SEEK_SET);
if (offset == -1)
{
perror("lseek");
exit(EXIT_FAILURE);
}
numWrite = write(fd, "asd", 3);
if (numWrite != 3)
{
perror("write");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
运行此程序发现设定的offset无效,write的数据仍然在末尾加上。原因是,此时文件偏移量的移动和数据写已经被纳入同一原子文件。
二、文件控制操作:fcntl()
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fildes, int cmd, ...);
三、打开文件的标志状态
fcntl()的用途之一是针对一个打开的文件,获取或修改其访问模式以及状态标志。
获取标志F_GETFL。使用方法如下。
int flags, accessMode;
flags = fcntl(fd, F_GETFL);
if (flags == -1)
errExit("fcntl");
改变标志F_SETFL。