对文件I/O的一些探讨

参考书目: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: [email protected] 
    > 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。

四、文件描述符和打开文件之间的关系

这里写图片描述

猜你喜欢

转载自blog.csdn.net/qq_39023220/article/details/82467366