fcntl系统调用可以用来对已打开的文件描述符进行各种控制操作以改变已打开文件的的各种属性

函数原型:
 
  1. #include<unistd.h>
  2. #include<fcntl.h>
  3. int fcntl(int fd, int cmd);
  4. int fcntl(int fd, int cmd, long arg);
  5. int fcntl(int fd, int cmd ,struct flock* lock);
#include<unistd.h>
#include<fcntl.h>
int fcntl(int fd, int cmd);
int fcntl(int fd, int cmd, long arg);
int fcntl(int fd, int cmd ,struct flock* lock);

fcntl函数功能依据cmd的值的不同而不同。参数对应功能如下:

(1)F_DUPFD

与dup函数功能一样,复制由fd指向的文件描述符,调用成功后返回新的文件描述符,与旧的文件描述符共同指向同一个文件。

(2)F_GETFD

读取文件描述符close-on-exec标志

(3)F_SETFD

将文件描述符close-on-exec标志设置为第三个参数arg的最后一位

(4)F_GETFL

获取文件打开方式的标志,标志值含义与open调用一致

(5)F_SETF

设置文件打开方式为arg指定方式

文件记录锁是fcntl函数的主要功能。

记录锁:实现只锁文件的某个部分,并且可以灵活的选择是阻塞方式还是立刻返回方式

当fcntl用于管理文件记录锁的操作时,第三个参数指向一个struct flock *lock的结构体

  1. struct flock
  2. {
  3. short_l_type;    /*锁的类型*/
  4. short_l_whence;  /*偏移量的起始位置:SEEK_SET,SEEK_CUR,SEEK_END*/
  5. off_t_l_start;     /*加锁的起始偏移*/
  6. off_t_l_len;    /*上锁字节*/
  7. pid_t_l_pid;   /*锁的属主进程ID */
  8. };
struct flock
{
short_l_type; /*锁的类型*/
short_l_whence; /*偏移量的起始位置:SEEK_SET,SEEK_CUR,SEEK_END*/
off_t_l_start; /*加锁的起始偏移*/
off_t_l_len; /*上锁字节*/
pid_t_l_pid; /*锁的属主进程ID */
};

short_l_type用来指定设置共享锁(F_RDLCK,读锁)还是互斥锁(F_WDLCK,写锁).

当short_l_type的值为F_UNLCK时,传入函数中将解锁。

每个进程可以在该字节区域上设置不同的读锁。

但给定的字节上只能设置一把写锁,并且写锁存在就不能再设其他任何锁,且该写锁只能被一个进程单独使用。

这是多个进程的情况。

单个进程时,文件的一个区域上只能有一把锁,若该区域已经存在一个锁,再在该区域设置锁时,新锁会覆盖掉旧的锁,无论是写锁还时读锁。

l_whence,l_start,l_len三个变量来确定给文件上锁的区域。

l_whence确定文件内部的位置指针从哪开始,l_star确定从l_whence开始的位置的偏移量,两个变量一起确定了文件内的位置指针先所指的位置,即开始上锁的位置,然后l_len的字节数就确定了上锁的区域。

特殊的,当l_len的值为0时,则表示锁的区域从起点开始直至最大的可能位置,就是从l_whence和l_start两个变量确定的开始位置开始上锁,将开始以后的所有区域都上锁。

为了锁整个文件,我们会把l_whence,l_start,l_len都设为0。

(6)F_SETLK

此时fcntl函数用来设置或释放锁。当short_l_type为F_RDLCK为读锁,F_WDLCK为写锁,F_UNLCK为解锁。

如果锁被其他进程占用,则返回-1;

这种情况设的锁遇到锁被其他进程占用时,会立刻停止进程。

(7)F_SETLKW

此时也是给文件上锁,不同于F_SETLK的是,该上锁是阻塞方式。当希望设置的锁因为其他锁而被阻止设置时,该命令会等待相冲突的锁被释放。

(8)F_GETLK

第3个参数lock指向一个希望设置的锁的属性结构,如果锁能被设置,该命令并不真的设置锁,而是只修改lock的l_type为F_UNLCK,然后返回该结构体。如果存在一个或多个锁与希望设置的锁相互冲突,则fcntl返回其中的一个锁的flock结构。

====================================================================================================================================================

linux下串口的阻塞和非阻塞操作

[cpp] 

有两个可以进行控制串口阻塞性(同时控制read和write):一个是在打开串口的时候,open函数是否带O_NDELAY;第二个是可以在打开串口之后通过fcntl()函数进行控制。

阻塞的定义:

对于read,block指当串口输入缓冲区没有数据的时候,read函数将会阻塞在这里,移植到串口输入缓冲区中有数据可读取,read读到了需要的字节数之后,返回值为读到的字节数;

对于write,block指当串口输出缓冲区满,或剩下的空间小于将要写入的字节数,则write将阻塞,一直到串口输出缓冲区中剩下的空间大于等于将要写入的字节数,执行写入操作,返回写入的字节数。

非阻塞的定义:

对于read,no block指当串口输入缓冲区没有数据的时候,read函数立即返回,返回值为0。

对于write,no block指当串口输出缓冲区满,或剩下的空间小于将要写入的字节数,则write将进行写操作,写入当前串口输出缓冲区剩下空间允许的字节数,然后返回写入的字节数。

  1. static int set_opt(int fd, int nSpeed, int nBits, char nEvent, int nStop)
  2. {
  3. struct termios newtio;
  4. struct termios oldtio;
  5. if(tcgetattr(fd,&oldtio) != 0)
  6. {
  7. perror("SetupSerial 1");
  8. return -1;
  9. }
  10. bzero(&newtio,sizeof(newtio));
  11. newtio.c_cflag |= CLOCAL |CREAD;
  12. newtio.c_cflag &= ~CSIZE;
  13. /***********数据位选择****************/
  14. switch(nBits)
  15. {
  16. case 7:
  17. newtio.c_cflag |= CS7;
  18. break;
  19. case 8:
  20. newtio.c_cflag |= CS8;
  21. break;
  22. }
  23. /***********校验位选择****************/
  24. switch(nEvent)
  25. {
  26. case 'O':
  27. newtio.c_cflag |= PARENB;
  28. newtio.c_cflag |= PARODD;
  29. newtio.c_iflag |= (INPCK | ISTRIP);
  30. break;
  31. case 'E':
  32. newtio.c_iflag |= (INPCK |ISTRIP);
  33. newtio.c_cflag |= PARENB;
  34. newtio.c_cflag &= ~PARODD;
  35. break;
  36. case 'N':
  37. newtio.c_cflag &= ~PARENB;
  38. break;
  39. }
  40. /***********波特率选择****************/
  41. switch(nSpeed)
  42. {
  43. case 2400:
  44. cfsetispeed(&newtio,B2400);
  45. cfsetospeed(&newtio,B2400);
  46. break;
  47. case 4800:
  48. cfsetispeed(&newtio,B4800);
  49. cfsetospeed(&newtio,B4800);
  50. break;
  51. case 9600:
  52. cfsetispeed(&newtio,B9600);
  53. cfsetospeed(&newtio,B9600);
  54. break;
  55. case 57600:
  56. cfsetispeed(&newtio,B57600);
  57. cfsetospeed(&newtio,B57600);
  58. break;
  59. case 115200:
  60. cfsetispeed(&newtio,B115200);
  61. cfsetospeed(&newtio,B115200);
  62. break;
  63. case 460800:
  64. cfsetispeed(&newtio,B460800);
  65. cfsetospeed(&newtio,B460800);
  66. break;
  67. default:
  68. cfsetispeed(&newtio,B9600);
  69. cfsetospeed(&newtio,B9600);
  70. break;
  71. }
  72. /***********停止位选择****************/
  73. if(nStop == 1){
  74. newtio.c_cflag &= ~CSTOPB;
  75. }
  76. else if(nStop ==2){
  77. newtio.c_cflag |= CSTOPB;
  78. }
  79. newtio.c_cc[VTIME] = 1;
  80. newtio.c_cc[VMIN] = FRAME_MAXSIZE;   //阻塞条件下有效
  81. tcflush(fd,TCIFLUSH);
  82. if((tcsetattr(fd,TCSANOW,&newtio)) != 0)
  83. {
  84. perror("com set error");
  85. return -1;
  86. }
  87. printf("set done!\n");
  88. return 0;
  89. }
  1. static int open_port(int fd,int comport)
  2. {
  3. /***********打开串口1****************/
  4. if(comport == 1)
  5. {
  6. fd = open("/dev/ttyAT1",O_RDWR|O_NOCTTY|O_NDELAY);
  7. if(fd == -1){
  8. perror("Can't Open Serial Port");
  9. return -1;
  10. }
  11. }
  12. /***********打开串口2****************/
  13. else if(comport == 2)
  14. {
  15. fd = open("/dev/ttyAT2",O_RDWR|O_NOCTTY|O_NDELAY);
  16. if(fd == -1){
  17. perror("Can't Open Serial Port");
  18. return -1;
  19. }
  20. }
  21. /***********打开串口3****************/
  22. else if(comport == 3)
  23. {
  24. fd = open("/dev/ttyAT3",O_RDWR|O_NOCTTY|O_NDELAY);
  25. if(fd == -1){
  26. perror("Can't Open Serial Port");
  27. return -1;
  28. }
  29. }
  30. if(comport == 1)
  31. {
  32. if(fcntl(fd,F_SETFL,FNDELAY) < 0)//非阻塞,覆盖前面open的属性
  33. {
  34. printf("fcntl failed\n");
  35. }
  36. else{
  37. printf("fcntl=%d\n",fcntl(fd,F_SETFL,FNDELAY));
  38. }
  39. }
  40. else
  41. {
  42. if(fcntl(fd,F_SETFL,0) < 0){   //阻塞,即使前面在open串口设备时设置的是非阻塞的,这里设为阻塞后,以此为准
  43. printf("fcntl failed\n");
  44. }
  45. else{
  46. printf("fcntl=%d\n",fcntl(fd,F_SETFL,0));
  47. }
  48. }
  49. if(isatty(STDIN_FILENO) == 0){
  50. printf("standard input is not a terminal device\n");
  51. }
  52. else{
  53. printf("isatty sucess!\n");
  54. }
  55. printf("fd-open=%d\n",fd);
  56. return fd;
  57. }

所以,linux的串口的阻塞性通过fcntl()函数进行设置即可。

  1. 阻塞:fcntl(fd,F_SETFL,0)
  1. 非阻塞:fcntl(fd,F_SETFL,FNDELAY

fcntl函数的用法总结的更多相关文章

  1. linxu fcntl 函数用法 【转】

    功能描述:根据文件描述词来操作文件的特性. 文件控制函数         fcntl -- file control 头文件: #include <fcntl.h>;          i ...

  2. Linux下 fcntl 函数用法说明

    功能描述:根据文件描述词来操作文件的特性. 文件控制函数         fcntl -- file control LIBRARY         Standard C Library (libc, ...

  3. fcntl函数用法详解

    功能描述:根据文件描述词来操作文件的特性. #include <unistd.h> #include <fcntl.h>  int fcntl(int fd, int cmd) ...

  4. fcntl函数用法——操纵文件描述符状态

    fcntl函数:操纵文件描述符,改变已经打开的文件的属性int fcntl(int fd, int cmd, ... //arg  );cmd选项:一.复制文件描述符:F_DUPFD二.更改设置文件描 ...

  5. fcntl函数用法——设置文件锁

    fcntl函数.锁定文件,设置文件锁.设置获取文件锁:F_GETLK .F_SETLK  .F_SETLKW文件锁结构,设置好用于fcntl函数的第三个参数.struct flock{    shor ...

  6. Linux系统编程(3)——文件与IO之fcntl函数

    linux文件I/O用:open.read.write.lseek以及close函数实现了文件的打开.读写等基本操作.fcntl函数可以根据文件描述词来操作文件. 用法: int fcntl(int ...

  7. Daemon函数的用法

    Daemon函数的用法 说明: 让一个程序后台运行. 原型: #include <unistd.h> int daemon(int nochdir, int noclose); #incl ...

  8. 有关日期的函数操作用法总结,to_date(),trunc(),add_months();

    相关知识链接: Oracle trunc()函数的用法 oracle add_months函数 Oracle日期格式转换,tochar(),todate() №2:取得当前日期是一个星期中的第几天,注 ...

  9. Oracle to_date()函数的用法

    Oracle to_date()函数的用法 to_date()是Oracle数据库函数的代表函数之一,下文对Oracle to_date()函数的几种用法作了详细的介绍说明,供您参考学习. 在Orac ...

随机推荐

  1. 【刷题】BZOJ 1565 [NOI2009]植物大战僵尸

    Description Plants vs. Zombies(PVZ)是最近十分风靡的一款小游戏.Plants(植物)和Zombies(僵尸)是游戏的主角,其中Plants防守,而Zombies进攻. ...

  2. 旧题新做:从idy的视角看数据结构

    “今天你不写总结……!!!” 额…… 还是讲我的吧.这些考试都是idy出的题. 20170121:DFS序. ST表.线段树练习 这是第一次考数据结构. Problem 1. setsum 1 sec ...

  3. mac下Android Studio使用及快捷键

    1.Android Studio使用及快捷键 (1)我们新建一个项目后进入界面,左侧可以选择Project或Android,一般选Project会比较习惯以前eclipse的显示 (2)点击左上角An ...

  4. C++下实现同接口下多个类作为参数的调用和传参

    /* 实现同接口下不同类的对象的转移 定义类的接口 定义多个继承该接口的类 定义管理类,把接口当作类型, 传入该接口下各种类的对象,进行操作 */ #include<iostream> # ...

  5. Git2:Git基本操作

    目录 一.git全局配置 二.创建一个版本库 三.git的常用操作 1.版本提交与回退 1.1.版本提交 1.2.版本回退 2.工作区.版本库与暂存区 2.1.工作区 2.2.版本库 3.管理文件的修 ...

  6. NATS_04:NATS协议详解

    NATS的协议是一个简单的.基于文本的发布/订阅风格的协议.客户端连接到 gnatsd(NATS服务器),并与 gnatsd 进行通信,通信基于普通的 TCP/IP 套接字,并定义了很小的操作集,换行 ...

  7. Pycharm远程连接服务器,并在本地调试服务器代码

    问题描述 其实有很多教程了,我只是想记录一下设置得记录,这样就能充分利用阿里云服务器为我跑代码了... 步骤一:配置deployment 步骤二:选择远程python解释器 步骤三:将本地文件上传至远 ...

  8. gitlab的备份与恢复与迁移

    一.gitlab的备份1.1 创建备份目录,并授权 1 2 3 4 [root@linux-node1 ~]# mkdir /data/backups/gitlab -p [root@linux-no ...

  9. vue ESLint自动修复

    在package.json文件中的"lint"里面加入--fix 然后终端里输入:npm run lint 1. vue用命令直接修复ESLint

  10. c#+js 使用formdata上传文件

    如果不是使用form表单submit的形式,我们可以手动通过formdata传值(针对文件上传等) 比如: <html> <head> <meta name=" ...