简单文件I/O编程之fcntl

    在文件I/O编程之一的基础上,本文主要讨论函数fcntl的用法及其注意事项。

    在Linux中,实现文件上锁的函数有lock和fcntl,其中lock对应的是建议性锁,而fcntl不仅可以施加建议性锁,也可以施加强制锁。同时,fcntl能对文件的某一记录上锁,也就是记录锁。

 

    fcntl函数原型:int fcntl(int fd, int cmd, struct flock *lock)

    函数传入值:

    fd为文件描述符。

    cmd为控制命令,主要有以下若干情况:

    F_DUPFD:用来查找大于或等于参数arg的最小且仍未使用的文件描述词,并且复制参数fd的文件描述词。执行成功则返回新复制的文件描述词。

    F_GETFD:取得close-on-exec旗标。若此旗标的FD_CLOEXEC位为0,代表在调用exec()相关函数时文件将不会关闭。
    F_SETFD:设置close-on-exec 旗标。该旗标以参数arg 的FD_CLOEXEC位决定。
    F_GETFL: 取得文件描述词状态旗标,此旗标为open()的参数flags。
    F_SETFL: 设置文件描述词状态旗标,参数arg为新旗标,但只允许O_APPEND、O_NONBLOCK和O_ASYNC位的改变,其他位的改变将不受影响。
    F_GETLK: 取得文件锁定的状态。
    F_SETLK: 设置文件锁定的状态。此时flcok 结构的l_type 值必须是F_RDLCK、F_WRLCK或F_UNLCK。如果无法建立锁定,则返回-1,错误代码为EACCES 或EAGAIN。
    F_SETLKW: F_SETLK 作用相同,但是无法建立锁定时,此调用会一直等到锁定动作成功为止。

   

    lock为flcok结构体,结构定义如下:

    struct flcok
    {
        short int l_type; /* 锁定的状态*/
        short int l_whence;/*决定l_start位置*/
        off_t l_start; /*锁定区域的开头位置*/ 
        off_t l_len; /*锁定区域的大小*/
        pid_t l_pid; /*锁定动作的进程*/
    };

    其中l_type有三种状态:

    F_RDLCK 建立一个供读取用的锁定
    F_WRLCK 建立一个供写入用的锁定 
    F_UNLCK 删除之前建立的锁定

   

    l_whence有三种状态:

    SEEK_SET 以文件开头为锁定的起始位置 
    SEEK_CUR 以目前文件读写位置为锁定的起始位置
    SEEK_END 以文件结尾为锁定的起始位置

 

   

    fcntl使用实例如下:

    void lock_set(int fd, int type) { struct flock lock; lock.l_whence = SEEK_SET; lock.l_start = 0; lock.l_len = 0; for (;;) { lock.l_type = type; //根据不同的type值给文件上锁或解锁 if((fcntl(fd, F_SETLK, &lock)) == 0) { if(lock.l_type == F_RDLCK) printf("read lock set by %d/n", getpid()); else if(lock.l_type == F_WRLCK) printf("write lock set by %d/n", getpid()); else if(lock.l_type == F_UNLCK) printf("release lock by %d/n", getpid()); return; } fcntl(fd, F_GETLK, &lock); //判断文件能否上锁 if(lock.l_type != F_UNLCK) //判断不能上锁原因 { if(lock.l_type == F_RDLCK) //已有读取锁 printf("read lock already set by %d/n", lock.l_pid); else if(lock.l_type == F_WRLCK) //已有写入锁 printf("write lock already set by %d/n", lock.l_pid); getchar(); } } }

 

 

    在主程序里,我们只需要打开需要读写的文件(已介绍),把锁分为写入锁和读取锁。

    写入锁操作:

    lock_set(fd, F_WRLCK);

    ...

    lock_set(fd, F_UNLCK);

 

    编译后,在两个终端分别运行该执行文件,有心的朋友自己测试一下吧(其实是我偷懒不截图)

 

    读取锁操作:

    lock_set(fd, F_RDLCK);

    ...

    lock_set(fd, F_UNLCK);

 

    同样的操作流程,根据上述两个流程,我们可以自己证明得到:写入锁是互斥锁,读取锁是共享锁。

 

 

    PS:一个小技巧:为了加锁整个文件,常将l_start设置为0,l_whence设置为SEEK_SET,l_len设置为0。

 

 

   

你可能感兴趣的:(编程,linux,struct,cmd,测试,终端)