fcntl和select函数彻底搞明白

fcntl和select函数彻底搞明白fcntl 和 select 函数彻底搞明白 nbsp 第一 fcntl 函数详细使用 nbsp nbsp nbsp nbsp nbsp nbsp fcntl 有强大的功能 它能够复制一个现有的描述符 获得 设置文件描述符标记 获得 设置文件状态标记 获得 设置异步 I O 所有权 获得 设置纪录锁 当多个用户共同使用 操作一个文件的情况 Linux 通常采用的方法就是给文件上锁 来避免共享资源产生竞争的状态 fcntl 文件锁有两种类型 建议性锁和强制

fcntl和select函数彻底搞明白

 

第一、fcntl函数详细使用      

fcntl有强大的功能,它能够复制一个现有的描述符,获得/设置文件描述符标记,获得/设置文件状态标记,获得/设置异步I/O所有权,获得/设置纪录锁。

当多个用户共同使用,操作一个文件的情况,Linux通常采用的方法就是给文件上锁,来避免共享资源产生竞争的状态。

fcntl文件锁有两种类型:建议性锁和强制性锁
         建议性锁是这样规定的:每个使用上锁文件的进程都要检查是否有锁存在,当然还得尊重已有的锁。内核和系统总体上都坚持不使用建议性锁,它们依靠程序员遵守这个规定。
         强制性锁是由内核执行的。当文件被上锁来进行写入操作时,在锁定该文件的进程释放该锁之前,内核会阻止任何对该文件的读或写访问,每次读或写访问都得检查锁是否存在。

        使用fcntl文件锁进行I/O操作必须小心:进程在开始任何I/O操作前如何去处理锁,在对文件解锁前如何完成所有的操作,是必须考虑的。如果在设置锁之前打开文件,或者读取该锁之后关闭文件,另一个进程就可能在上锁/解锁操作和打开/关闭操作之间的几分之一秒内访问该文件。当一个进程对文件加锁后,无论它是否释放所加的锁,只要文件关闭,内核都会自动释放加在文件上的建议性锁(这也是建议性锁和强制性锁的最大区别), 所以不要想设置建议性锁来达到永久不让别的进程访问文件的目的(强制性锁才可以)^_^;强制性锁则对所有进程起作用。

      可以用fcntl 函数改变一个已打开的文件的属性,可以重新设置读、写、追加、非阻塞等标志(这些标志称为File StatusFlag),而不必重新open 文件。

     #include


      #include


      int fcntl(int fd, int cmd);
      int fcntl(int fd, int cmd, long arg);
      int fcntl(int fd, int cmd, struct flock *lock);





这个函数和open 一样,也是用可变参数实现的,可变参数的类型和个数取决于前面的cmd 参数。

文件锁包括了建议性锁强制性锁。



建议性锁要求每个上锁的文件的进程都要检查是否有锁存在,并且尊重已有的锁,在一般情况下,内核和系统都不使用建议性锁。



强制性锁是由内核执行的锁,当一个文件被上锁进行读写操作的时候,内核将阻止其他任何文件对其进行读写操作。每次读写操作都要检查是否有锁存在。



Linux中实现上锁的函数有lock()fcntl()

lock()

用于对文件施加建议性锁
fcntl()
用于对文件施加建议性锁和强制性锁都行。同时还可以对文件某一条纪录进行上锁,也就是记录锁。



记录锁分为读取锁(共享锁,它能够使多个进程都能在文件的同一部分建立读取锁)写入锁(排斥锁,在任何时刻只能有一个进程在文件的某部分建立写入锁。)。

fcntl

函数原型
#include


#include


#include

int fcntl(int fd,   //







文件描述符
          int cmd , //
不同的命令
          struct flock *lock) //
设置记录锁的具体状态

cmd

取值:
F_DUPFD  
复制文件描述符
F_GETFD  
获得fdclose-on-exec标志
F_SETFD  
设置close-on-exec标志
F_GETFL  
获得open设置标志
F_SETFL  
设置lock描述的标志
F_GETLK  
测试该锁是否被另外一把锁排斥
F_SETLKW
如果存在其他锁,则调用进程睡眠,如果捕捉到信号则睡眠中断
F_GETOWN
检索收到的SIGIOSIGURG信号的进程号或者进程组号
F_SETOWN
设置进程号或进程组号



这里的lock结构体如下:
struct flock
{
    short l_type;   /*F_RDLCK(


读取锁),F_WRLCK(写入锁),F_UNLCK(解锁)*/
    off_t l_start; /*
相对偏移量(字节)*/
    short l_whence; /*SEEK_SET ,SEEK_CUR ,SEEK_END */
    off_t l_len;    /*

加锁区域长度*/
    pid_t l_pid;
}





成功:0

出错:-1

提示:如果加锁整个文件通常的方法是将l_start设置为0l_whence设置为SEEK_SET, l_len设置为0

      下面的例子使用F_GETFLF_SETFL这两种fcntl 命令改变STDIN_FILENO的属性上O_NONBLOCK 选项,实现非阻塞读终端的功能。

用fcntl改变File Status Flag







第二、select函数详细使用   

struct timeval {

             long    tv_sec;         /* seconds */
             long    tv_usec;        /* microseconds */
         };


fd_set rdfds; /* 先申明一个 fd_set 集合来保存我们要检测的 socket句柄 */
struct timeval tv; /*
申明一个时间变量来保存时间 */
int ret; /*
保存返回值 */
FD_ZERO(&rdfds); /*
select函数之前先把集合清零 */
FD_SET(socket, &rdfds); /*
把要检测的句柄socket加入到集合里 */
tv.tv_sec = 1;
tv.tv_usec = 500; /*

设置select等待的最大时间为1秒加500毫秒 */
ret = select(socket + 1, &rdfds, NULL, NULL, &tv); /*
检测我们上面设置到集合rdfds里的句柄是否有可读信息 */
if(ret < 0) perror("select");/*
这说明select函数出错 */
else if(ret == 0) printf(“
超时\n”); /* 说明在我们设定的时间值1秒加500毫秒的时间内,socket的状态没有发生变化 */
else { /*
说明等待时间还未到1秒加500毫秒,socket的状态发生了变化 */
    printf(“ret=%d\n”, ret); /* ret
这个返回值记录了发生状态变化的句柄的数目,由于我们只监视了socket这一个句柄,所以这里一定ret=1,如果同时有多个句柄发生变化返回的就是句柄的总和了 */
    /*
这里我们就应该从socket这个句柄里读取数据了,因为select函数已经告诉我们这个句柄里有数据可读 */
    if(FD_ISSET(socket, &rdfds)) { /*
先判断一下socket这外被监视的句柄是否真的变成可读的了 */
        /*
读取socket句柄里的数据 */
        recv(…);
    }
}


int maxfd = 0;
if(sa > maxfd) maxfd = sa;
if(sb > maxfd) maxfd = sb;
if(sc > maxfd) maxfd = sc;


然后调用select函数:

ret = select(maxfd + 1,&rdfds, NULL, NULL, &tv); /* 注意是最大值还要加1 */

同样的道理,如果我们要检测用户是否按了键盘进行输入,我们就应该把标准输入0这个句柄放到select里来检测,如下:

FD_ZERO(&rdfds);
FD_SET(0, &rdfds);
tv.tv_sec = 1;
tv.tv_usec = 0;
ret = select(1, &rdfds, NULL, NULL, &tv); /*



注意是最大值还要加1 */
if(ret < 0) perror("select");/*
出错 */
else if(ret == 0) printf(“
超时\n”); /* 在我们设定的时间tv内,用户没有按键盘 */
else { /*
用户有按键盘,要读取用户的输入 */
    scanf(“%s”, buf);
}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/222266.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月17日 下午4:11
下一篇 2026年3月17日 下午4:11


相关推荐

  • 网页音乐播放器代码

    网页音乐播放器代码网页音乐播放器代码如果你也想往自己的博客里,网页里加入音乐播放器,只要复制下面的网页音乐播放器代码,做适当的修改就可以啦!有很多播放器可以选择,不要挑花眼哦!中true或1表示自动播放,false或0表示手动播放loop=”true”中的true或1表示重复播放,f

    2022年6月16日
    37
  • lofter限流怎么解决_高并发限流

    lofter限流怎么解决_高并发限流前言:学习本篇博客是有一些前提基础的1、熟悉gateway网关使用2、熟悉nginx使用3、熟悉sentinel的应用,会涉及网关规则持久化改造看不懂的童鞋们可以补一下微服务gateway网关和Sentinel相关知识秒杀链路兜底方案之限流&降级实战一、秒杀场景介绍1.1秒杀场景的特点1.2流量消峰1.3兜底方案二、限流实战2.1nginx限流(https://nginx.org/en/docs)2.2网关限流2.2.1网关接入sentinel控制台2.2.2Sentinel

    2022年10月6日
    4
  • scss和sass的区别,scss的基本使用

    scss和sass的区别,scss的基本使用sass 和 scss 有什么关系 1 sass 和 scss 其实是一样的 css 预处理语言 SCSS 是 Sass3 引入新的语法 其后缀名是分别为 sass 和 scss 两种 2 SASS 版本 3 0 之前的后缀名为 sass 而版本 3 0 之后的后缀名 scss 3 两者是有不同的 继 sass 之后 scss 的编写规范基本和 css 一致 sass 时代是有格的缩进规范并且没有 和 而 scss 则和 css 的规范是一致的 为了方便应用 scss 我们可以在 vscode 中安装一个名为 easysass

    2026年3月18日
    2
  • TT-付款方式_后tt付款方式是货到付款吗

    TT-付款方式_后tt付款方式是货到付款吗付款方式 一般T/T是可以的,上述客户我们采用的付款方式就是定金加TT,如果是信用证方式,那么需要资信良好的开证行: 中国工商银行 汇丰银行 渣打银行&#160

    2022年8月1日
    9
  • windows 批量杀掉进程_win7杀死进程

    windows 批量杀掉进程_win7杀死进程有时候由于病毒或其他原因,启动了一系列的进程,并且有时杀了这个,又多了那个。使用命令taskkill可将这些进程一下子全部杀光:C:\Users\NR>taskkill/F/imfrontpg.exe成功:已终止进程”FRONTPG.EXE”,其PID为3732。成功:已终止进程”FRONTPG.EXE”,其PID为24544。成功:已终止进程”FRO

    2025年12月10日
    5
  • ideaIU-2021.10.1 激活码【最新永久激活】

    (ideaIU-2021.10.1 激活码)2021最新分享一个能用的的激活码出来,希望能帮到需要激活的朋友。目前这个是能用的,但是用的人多了之后也会失效,会不定时更新的,大家持续关注此网站~IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/100143.html…

    2022年3月27日
    150

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号