热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

linux系统编程之文件与I/O(六):fcntl函数与

一、fcntl函数 功能:操纵文件描述符,改变已打开的文件的属性 int fcntl(int fd, int


一、fcntl函数


功能:操纵文件描述符,改变已打开的文件的属性




int fcntl(int fd, int cmd, ... /* arg */ );








cmd的取值可以如下:


复制文件描述符


F_DUPFD (long)




设置/获取文件描述符标志


F_GETFD (void)


F_SETFD (long)




设置/获取文件状态标志


F_GETFL (void)


F_SETFL (long)




获取/设置文件锁


F_GETLK


F_SETLK,F_SETLKW








其中复制文件描述符可参见《

linux系统编程之文件与I/O(五):打开文件的内核结构file和重定向

》,文件描述符的标志只有一个即FD_CLOEXEC,设置/获取文件描述符标志等学习到进程部分再说。下面先来看设置/获取文件状态标志。


F_SETFL:


On Linux  this  command can change only the O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME, and O_NONBLOCK flags.




示例程序如下:

 



 C++ Code 












1



2



3



4



5



6



7



8



9



10



11



12



13



14



15



16



17



18



19



20



21



22



23



24



25



26



27



28



29



30



31



32



33



34



35



36



37



38



39



40



41



42



43



44



45



46



47



48



49



50



51



52



53



54



55



56



57



58



59



60



61



62



63



64



65



66



67





 



/*************************************************************************


    > File Name: file_fcntl.c


    > Author: Simba


    > Mail: dameng34@163.com


    > Created Time: Sat 23 Feb 2013 02:34:02 PM CST


 ************************************************************************/




#include






#include






#include






#include






#include






#include






#include






#include








#define

 ERR_EXIT(m) \



    


do

 { \



        perror(m); \



        exit(EXIT_FAILURE); \



    } 


while

(


0

)






void

 set_flag(


int




int

);




void

 clr_flag(


int




int

);






int

 main(


int

 argc, 


char

 *argv[])



{



    


char

 buf[


1024

] = {


0

};



    


int

 ret;



    


/*


        int flags;


        flags = fcntl(0, F_GETFL, 0);


        if (flags == -1)


            ERR_EXIT("fcntl get flag error");


        ret = fcntl(0, SETFL, flags | O_NONBLOCK); //设置为非阻塞,但不更改其他状态


        if (ret == -1)


            ERR_EXIT("fcntl set flag error");


    */



    set_flag(


0

, O_NONBLOCK);



    ret = read(


0

, buf, 


1024

);



    


if

 (ret == -


1

)



        ERR_EXIT(


"read error"

);





    printf(


"buf=%s\n"

, buf);



    


return

 


0

;



}






void

 set_flag(


int

 fd, 


int

 flags)



{



    


int

 val;



    val = fcntl(fd, F_GETFL, 


0

);



    


if

 (val == -


1

)



        ERR_EXIT(


"fcntl get flag error"

);



    val |= flags;



    


if

 (fcntl(fd, F_SETFL, val) < 


0

)



        ERR_EXIT(


"fcntl set flag error"

);



}






void

 clr_flag(


int

 fd, 


int

 flags)



{



    


int

 val;



    val = fcntl(fd, F_GETFL, 


0

);



    


if

 (val == -


1

)



        ERR_EXIT(


"fcntl get flag error"

);



    val &= ~flags;



    


if

 (fcntl(fd, F_SETFL, val) < 


0

)



        ERR_EXIT(


"fcntl set flag error"

);



}



测试输出:

 


simba@ubuntu:~/Documents/code/linux_programming/APUE/File_IO$ ./file_fcntl 


read error: Resource temporarily unavailable




因为将标准输入的状态更改为非阻塞,则read不会阻塞等待输入而立即返回错误,errno将被置为EAGAIN,即可以重新尝试。




二、文件锁结构体


struct flock {


...


short l_type;       /* Type of lock: F_RDLCK,


        F_WRLCK, F_UNLCK */


short l_whence; /* How to interpret l_start:


                                   SEEK_SET, SEEK_CUR, SEEK_END */


off_t l_start;       /* Starting offset for lock */


off_t l_len;         /* Number of bytes to lock */


pid_t l_pid;        /* PID of process blocking our lock


                                   (F_GETLK only) */


     ...


};




文件锁的类型只有两种,一种是写锁也叫排他锁,一种是读锁也就共享锁,可以有多个进程各持有一个读锁,但只能有一个进程持有写锁,只有对文件有对应的读写权限才能施加对应的锁类型。中间三个参数 l_whence,  l_start, l_len 决定了被锁定的文件范围。当fcntl 函数的cmd为F_GETLK时,flock 结构体的 l_pid 参数会返回持有某种类型锁的进程id。进程退出或者文件描述符被关闭时,会释放所有的锁。






示例程序如下:

 



 C++ Code 












1



2



3



4



5



6



7



8



9



10



11



12



13



14



15



16



17



18



19



20



21



22



23



24



25



26



27



28



29



30



31



32



33



34



35



36



37



38



39



40



41



42



43



44



45



46



47



48



49



50



51



52



53





 



/*************************************************************************


    > File Name: file_flock.c


    > Author: Simba


    > Mail: dameng34@163.com


    > Created Time: Sat 23 Feb 2013 02:34:02 PM CST


 ************************************************************************/




#include






#include






#include






#include






#include






#include






#include






#include








#define

 ERR_EXIT(m) \



    


do

 { \



        perror(m); \



        exit(EXIT_FAILURE); \



    } 


while

(


0

)








int

 main(


int

 argc, 


char

 *argv[])



{



    


int

 fd;



    fd = open(


"test2.txt"

, O_CREAT | O_RDWR | O_TRUNC, 


0664

);



    


if

 (fd == -


1

)



        ERR_EXIT(


"open error"

);



    


/* 只有对文件有相应的读写权限才能施加对应的文件锁 */



    


struct

 flock lock;



    memset(&lock, 


0




sizeof

(lock));



    lock.l_type = F_WRLCK; 


// 排他锁,即不允许其他进程再对其加任何类型的锁,但读锁(共享锁)允许



    lock.l_whence = SEEK_SET;



    lock.l_start = 


0




//从文件开头开始锁定



    lock.l_len = 


0




// 文件全部内容锁住





    


if

 (fcntl(fd, F_SETLK, &lock) == 


0

)



    {



        


/* 若为F_SETLKW,这时如果锁已经被其他进程占用,则此进程会阻塞直到其他进程释放锁*/



        printf(


"lock success\n"

);



        printf(


"press any key to unlock\n"

);



        getchar();



        lock.l_type = F_UNLCK;



        


if

 (fcntl(fd, F_SETLK, &lock) == 


0

)



            printf(


"unlock success\n"

);



        


else



            ERR_EXIT(


"unlock fail"

);



    }



    


else



        ERR_EXIT(


"lock fail"

);





    


return

 


0




//进程退出会对所有文件解锁



}



 

 


测试如下:


我们先在一个 终端执行程序:


simba@ubuntu:~/Documents/code/linux_programming/APUE/File_IO$ ./file_flock 


lock success


press any key to unlock








现在文件已经被锁住了,而且没有按下任何按键,所以卡在这里,也还没解锁,接着在另一个终端再次执行同个程序:


simba@ubuntu:~/Documents/code/linux_programming/APUE/File_IO$ ./file_flock 


lock fail: Resource temporarily unavailable




会立即返回错误,因为我们希望施加的是排他锁,而现在前面一个进程正在占用写锁还没释放,所以尝试施加锁失败,而如果fcntl 函数的cmd 设置为 F_SETLKW,即带w的版本,则此进程会一直阻塞直到前面一个进程释放了锁。

 


linux系统编程之文件与I/O(六):fcntl 函数与文件锁




推荐阅读
  • 在Docker中,将主机目录挂载到容器中作为volume使用时,常常会遇到文件权限问题。这是因为容器内外的UID不同所导致的。本文介绍了解决这个问题的方法,包括使用gosu和suexec工具以及在Dockerfile中配置volume的权限。通过这些方法,可以避免在使用Docker时出现无写权限的情况。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • 本文详细介绍了SQL日志收缩的方法,包括截断日志和删除不需要的旧日志记录。通过备份日志和使用DBCC SHRINKFILE命令可以实现日志的收缩。同时,还介绍了截断日志的原理和注意事项,包括不能截断事务日志的活动部分和MinLSN的确定方法。通过本文的方法,可以有效减小逻辑日志的大小,提高数据库的性能。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 本文介绍了在Linux下安装Perl的步骤,并提供了一个简单的Perl程序示例。同时,还展示了运行该程序的结果。 ... [详细]
  • Linux磁盘的分区、格式化的观察和操作步骤
    本文介绍了如何观察Linux磁盘的分区状态,使用lsblk命令列出系统上的所有磁盘列表,并解释了列表中各个字段的含义。同时,还介绍了使用parted命令列出磁盘的分区表类型和分区信息的方法。在进行磁盘分区操作时,根据分区表类型选择使用fdisk或gdisk命令,并提供了具体的分区步骤。通过本文,读者可以了解到Linux磁盘分区和格式化的基本知识和操作步骤。 ... [详细]
  • imx6ull开发板驱动MT7601U无线网卡的方法和步骤详解
    本文详细介绍了在imx6ull开发板上驱动MT7601U无线网卡的方法和步骤。首先介绍了开发环境和硬件平台,然后说明了MT7601U驱动已经集成在linux内核的linux-4.x.x/drivers/net/wireless/mediatek/mt7601u文件中。接着介绍了移植mt7601u驱动的过程,包括编译内核和配置设备驱动。最后,列举了关键词和相关信息供读者参考。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • 本文介绍了在Windows系统上使用C语言命令行参数启动程序并传递参数的方法,包括接收参数程序的代码和bat文件的编写方法,同时给出了程序运行的结果。 ... [详细]
  • 如何查询zone下的表的信息
    本文介绍了如何通过TcaplusDB知识库查询zone下的表的信息。包括请求地址、GET请求参数说明、返回参数说明等内容。通过curl方法发起请求,并提供了请求示例。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文讨论了在Windows 8上安装gvim中插件时出现的错误加载问题。作者将EasyMotion插件放在了正确的位置,但加载时却出现了错误。作者提供了下载链接和之前放置插件的位置,并列出了出现的错误信息。 ... [详细]
  • 本文介绍了如何使用C#制作Java+Mysql+Tomcat环境安装程序,实现一键式安装。通过将JDK、Mysql、Tomcat三者制作成一个安装包,解决了客户在安装软件时的复杂配置和繁琐问题,便于管理软件版本和系统集成。具体步骤包括配置JDK环境变量和安装Mysql服务,其中使用了MySQL Server 5.5社区版和my.ini文件。安装方法为通过命令行将目录转到mysql的bin目录下,执行mysqld --install MySQL5命令。 ... [详细]
author-avatar
中国地产人
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有