fcntl的使用

功能描述:根据文件描述词来操作文件的特性。

#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()针对(文件)描述符提供控制。参数fd是被参数cmd操作(如下面的描述)的描述符。针对cmd的值,fcntl能够接受第三个参数int arg。

[返回值]
fcntl()的返回值
与命令有关。如果出错,所有命令都返回-1,如果成功则返回某个其他值。下列三个命令有特定返回值:F_DUPFD , F_GETFD , F_GETFL以及F_GETOWN。
    F_DUPFD   返回新的文件描述符
    F_GETFD   返回相应标志
    F_GETFL , F_GETOWN   返回一个正的进程ID或负的进程组ID

 

fcntl函数有5种功能: 
1. 复制一个现有的描述符(cmd=F_DUPFD). 
2. 获得/设置文件描述符标记(cmd=F_GETFD或F_SETFD). 
3. 获得/设置文件状态标记(cmd=F_GETFL或F_SETFL). 
4. 获得/设置异步I/O所有权(cmd=F_GETOWN或F_SETOWN). 
5. 获得/设置记录锁(cmd=F_GETLK , F_SETLK或F_SETLKW).

1. cmd值的F_DUPFD : 
F_DUPFD    返回一个如下描述的(文件)描述符:
        ·最小的大于或等于arg的一个可用的描述符
        ·与原始操作符一样的某对象的引用
        ·如果对象是文件(file)的话,则返回一个新的描述符,这个描述符与arg共享相同的偏移量(offset)
        ·相同的访问模式(读,写或读/写)
        ·相同的文件状态标志(如:两个文件描述符共享相同的状态标志)
        ·与新的文件描述符结合在一起的close-on-exec标志被设置成交叉式访问execve(2)的系统调用

实际上调用dup(oldfd);
等效于

        fcntl(oldfd, F_DUPFD, 0);

而调用dup2(oldfd, newfd);
等效于
        close(oldfd);
        fcntl(oldfd, F_DUPFD, newfd);

2. cmd值的F_GETFD和F_SETFD:      
F_GETFD    取得与文件描述符fd联合的close-on-exec标志,类似FD_CLOEXEC。如果返回值和FD_CLOEXEC进行与运算结果是0的话,文件保持交叉式访问exec(),否则如果通过exec运行的话,文件将被关闭(arg 被忽略)  
      
F_SETFD    设置close-on-exec标志,该标志以参数arg的FD_CLOEXEC位决定,应当了解很多现存的涉及文件描述符标志的程序并不使用常数 FD_CLOEXEC,而是将此标志设置为0(系统默认,在exec时不关闭)或1(在exec时关闭)    

在修改文件描述符标志或文件状态标志时必须谨慎,先要取得现在的标志值,然后按照希望修改它,最后设置新标志值。不能只是执行F_SETFD或F_SETFL命令,这样会关闭以前设置的标志位。 

3. cmd值的F_GETFL和F_SETFL:   
F_GETFL    取得fd的文件状态标志,如同下面的描述一样(arg被忽略),在说明open函数时,已说明
了文件状态标志。不幸的是,三个存取方式标志 (O_RDONLY , O_WRONLY , 以及O_RDWR)并不各占1位。(这三种标志的值各是0 , 1和2,由于历史原因,这三种值互斥 — 一个文件只能有这三种值之一。) 因此首先必须用屏蔽字O_ACCMODE相与取得存取方式位,然后将结果与这三种值相比较。       
F_SETFL    设置给arg描述符状态标志,可以更改的几个标志是:O_APPEND,O_NONBLOCK,O_SYNC 和 O_ASYNC。而fcntl的文件状态标志总共有7个:O_RDONLY , O_WRONLY , O_RDWR , O_APPEND , O_NONBLOCK , O_SYNC和O_ASYNC

可更改的几个标志如下面的描述:
    O_NONBLOCK   非阻塞I/O,如果read(2)调用没有可读取的数据,或者如果write(2)操作将阻塞,则read或write调用将返回-1和EAGAIN错误
    O_APPEND     强制每次写(write)操作都添加在文件大的末尾,相当于open(2)的O_APPEND标志
    O_DIRECT     最小化或去掉reading和writing的缓存影响。系统将企图避免缓存你的读或写的数据。如果不能够避免缓存,那么它将最小化已经被缓存了的数据造成的影响。如果这个标志用的不够好,将大大的降低性能
    O_ASYNC      当I/O可用的时候,允许SIGIO信号发送到进程组,例如:当有数据可以读的时候

4. cmd值的F_GETOWN和F_SETOWN:   
F_GETOWN   取得当前正在接收SIGIO或者SIGURG信号的进程id或进程组id,进程组id返回的是负值(arg被忽略)     
F_SETOWN   设置将接收SIGIO和SIGURG信号的进程id或进程组id,进程组id通过提供负值的arg来说明(arg绝对值的一个进程组ID),否则arg将被认为是进程id

 5. cmd值的F_GETLK, F_SETLK或F_SETLKW 获得/设置记录锁的功能,成功则返回0,若有错误则返回-1,错误原因存于errno。
F_GETLK    通过第三个参数arg(一个指向flock的结构体)取得第一个阻塞lock description指向的锁。取得的信息将覆盖传到fcntl()的flock结构的信息。如果没有发现能够阻止本次锁(flock)生成的锁,这个结构将不被改变,除非锁的类型被设置成F_UNLCK    
F_SETLK    按照指向结构体flock的指针的第三个参数arg所描述的锁的信息设置或者清除一个文件的segment锁。F_SETLK被用来实现共享(或读)锁(F_RDLCK)或独占(写)锁(F_WRLCK),同样可以去掉这两种锁(F_UNLCK)。如果共享锁或独占锁不能被设置,fcntl()将立即返回EAGAIN     
F_SETLKW   除了共享锁或独占锁被其他的锁阻塞这种情况外,这个命令和F_SETLK是一样的。如果共享锁或独占锁被其他的锁阻塞,进程将等待直到这个请求能够完成。当fcntl()正在等待文件的某个区域的时候捕捉到一个信号,如果这个信号没有被指定SA_RESTART, fcntl将被中断

当一个共享锁被set到一个文件的某段的时候,其他的进程可以set共享锁到这个段或这个段的一部分。共享锁阻止任何其他进程set独占锁到这段保护区域的任何部分。如果文件描述符没有以读的访问方式打开的话,共享锁的设置请求会失败。

独占锁阻止任何其他的进程在这段保护区域任何位置设置共享锁或独占锁。如果文件描述符不是以写的访问方式打开的话,独占锁的请求会失败。

结构体flock的指针:
struct flcok 

short int l_type; /* 锁定的状态*/

//以下的三个参数用于分段对文件加锁,若对整个文件加锁,则:l_whence=SEEK_SET, l_start=0, l_len=0
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文件锁有两种类型:建议性锁和强制性锁
建议性锁是这样规定的:每个使用上锁文件的进程都要检查是否有锁存在,当然还得尊重已有的锁。内核和系统总体上都坚持不使用建议性锁,它们依靠程序员遵守这个规定。
强制性锁是由内核执行的:当文件被上锁来进行写入操作时,在锁定该文件的进程释放该锁之前,内核会阻止任何对该文件的读或写访问,每次读或写访问都得检查锁是否存在。

系统默认fcntl都是建议性锁,强制性锁是非POSIX标准的。如果要使用强制性锁,要使整个系统可以使用强制性锁,那么得需要重新挂载文件系统,mount使用参数 -0 mand 打开强制性锁,或者关闭已加锁文件的组执行权限并且打开该文件的set-GID权限位。
建议性锁只在cooperating processes之间才有用。对cooperating process的理解是最重要的,它指的是会影响其它进程的进程或被别的进程所影响的进程,举两个例子:
(1) 我们可以同时在两个窗口中运行同一个命令,对同一个文件进行操作,那么这两个进程就是cooperating  processes
(2) cat file | sort,那么cat和sort产生的进程就是使用了pipe的cooperating processes

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

fcntl使用三个参数 F_SETLK/F_SETLKW, F_UNLCK和F_GETLK 来分别要求、释放、测试record locks。record locks是对文件一部分而不是整个文件的锁,这种细致的控制使得进程更好地协作以共享文件资源。fcntl能够用于读取锁和写入锁,read lock也叫shared lock(共享锁), 因为多个cooperating process能够在文件的同一部分建立读取锁;write lock被称为exclusive lock(排斥锁),因为任何时刻只能有一个cooperating process在文件的某部分上建立写入锁。如果cooperating processes对文件进行操作,那么它们可以同时对文件加read lock,在一个cooperating process加write lock之前,必须释放别的cooperating process加在该文件的read lock和wrtie lock,也就是说,对于文件只能有一个write lock存在,read lock和wrtie lock不能共存。

下面的例子使用F_GETFL获取fd的文件状态标志

#include<fcntl.h>
#include<unistd.h>
#include<iostream>
#include<errno.h>
using namespace std;

int main(int argc,char* argv[])
{
  int fd, var;
  //  fd=open("new",O_RDWR);
  if (argc!=2)
  {
      perror("--");
      cout<<"请输入参数,即文件名!"<<endl;
  }

  if((var=fcntl(atoi(argv[1]), F_GETFL, 0))<0)
  {
     strerror(errno);
     cout<<"fcntl file error."<<endl;
  }

  switch(var & O_ACCMODE)
  {
   case O_RDONLY : cout<<"Read only.."<<endl;
                   break;
   case O_WRONLY : cout<<"Write only.."<<endl;
                   break;
   case O_RDWR   : cout<<"Read wirte.."<<endl;
                   break;
   default  : break;
  }

 if (val & O_APPEND)
    cout<<",append"<<endl;

 if (val & O_NONBLOCK)
    cout<<",noblocking"<<endl;

 cout<<"exit 0"<<endl;

 exit(0);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/383421.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

链表面试题1:反转单链表,不带头结点。

三个指针p1,p2,p3&#xff0c;p1指向头结点的前一个结点&#xff0c;也就时指空&#xff0c;p2指向头结点&#xff0c;p3指向头结点下一个结点。 p3指向p2的下一个&#xff0c;让p2指针域指向p1&#xff0c;让p1挪到p2上&#xff0c;再让p2指向p3.

dup/dup2函数的用法

系统调用dup和dup2能够复制文件描述符。dup返回新的文件文件描述符&#xff08;没有用的文件描述符最小的编号&#xff09;。dup2可以让用户指定返回的文件描述符的值&#xff0c;如果需要&#xff0c;则首先接近newfd的值&#xff0c;他通常用来重新打开或者重定向一个文件描述…

链表面试题2:编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前

我们可以&#xff0c;用两个新链表&#xff0c;一个存比基准值大的&#xff0c;另一个存比基准值小的。然后再拼接在一起。 用尾插的方法&#xff0c;首先说小的&#xff0c;创建两个指针&#xff0c;一个头&#xff0c;一个尾&#xff0c;再创建个指针跑链表&#xff0c;扫描…

文件系统缓存dirty_ratio与dirty_background_ratio两个参数区别

这两天在调优数据库性能的过程中需要降低操作系统文件Cache对数据库性能的影响&#xff0c;故调研了一些降低文件系统缓存大小的方法&#xff0c;其中一种是通过修改/proc/sys/vm/dirty_background_ration以及/proc/sys/vm/dirty_ratio两个参数的大小来实现。看了不少相关博文的…

栈和队列的基本操作(栈和队列的区别)

数据结构中的栈与内存中的栈的不同 一、数据结构中的堆栈 在数据结构中的堆栈&#xff0c;实际上堆栈是两种数据结构&#xff1a;堆和栈。堆和栈都是一种数据项按序排列的数据结构。 1.栈就像装数据的桶或箱子 我们先从大家比较熟悉的栈说起吧&#xff0c;它是一种具有后进先…

Linux I/O 调度方法

操作系统的调度有 CPU调度 CPU scheduler IO调度 IO scheduler IO调度器的总体目标是希望让磁头能够总是往一个方向移动,移动到底了再往反方向走,这恰恰就是现实生活中的电梯模型,所以IO调 度器也被叫做电梯. (elevator)而相应的算法也就被叫做电梯算法. 而Linux中I…

编译libcurl

1.下载源码后&#xff0c;执行./buidconf产生configure配置文件 2.通过build.sh来设定configure 配置的参数 #!/bin/sh # export CFLAGS-O3 -w -isystem /home/xuxuequan/Ingenicwork/toolchain/mips-gcc472-glibc216-32bit/mips-linux-gnu/libc/usr/include export CPPFLAGS…

链表面试题3:将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成 的。

链表面试题3&#xff1a;将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成 的。 首先我们的思想是将得一个链表和第二个链表的每个结点进行比较&#xff0c;谁小谁就插入到新链表的最后。 首先我们要判段链表是否为空&#xff0c;…

gcc编译参数-fPIC的一些问题

ppc_85xx-gcc -shared -fPIC liberr.c -o liberr.so-fPIC 作用于编译阶段&#xff0c;告诉编译器产生与位置无关代码(Position-Independent Code)&#xff0c;则产生的代码中&#xff0c;没有绝对地址&#xff0c;全部使用相对地址&#xff0c;故而代码可以被加载器加载到内存的…

双向链表的操作(创建,插入,删除)

双向链表的代码看似复杂&#xff0c;其实很简单&#xff0c;只要画图便可明白&#xff0c; 删除 假如要删除的结点叫pos. pos->prev->nextpos->next; pos->next->prevpos->prev; free(pos);

我使用过的Linux命令之hwclock - 查询和设置硬件时钟

我使用过的Linux命令之hwclock - 查询和设置硬件时钟 本文链接&#xff1a;http://codingstandards.iteye.com/blog/804830 &#xff08;转载请注明出处&#xff09; 用途说明 hwclock命令&#xff0c;与clock命令是同一个命令&#xff0c;主要用来查询和设置硬件时钟&#x…

二叉树的操作(前,中,后序遍历也叫深度优先遍历,非空结点的个数)递归实现

定义一个二叉树的结点 二叉树的前序遍历&#xff0c; 先访问根结点&#xff0c;再访问左&#xff0c;再访问右。 每次访问都要先看根结点是否为空&#xff0c;然后打印根结点&#xff0c;把此时根结点的左结点作为下一次递归的根结点&#xff0c;当把左结点遍历完后&#xff0…

makefile编译问题记录

1.-c选项和-C选项&#xff1a; -c&#xff08;gcc选项&#xff09;&#xff1a;编译.c或汇编源文件&#xff0c;但是不作连接. 编译器输出对应于源文件的目标文件. 如&#xff1a;$(CC) -c ${CFLAGS} ${SRCS} -C&#xff08;makefile选项&#xff09;&#xff1a;-C的是make…

二叉树的相关题(叶子结点个数,最大深度,找特殊值结点(值不重复),判断两个树是否相同,判断两个数是否为镜像树,是否为子树,)

叶子结点就是没有孩子结点&#xff0c;所以当当前根结点没有孩子结点的时候&#xff0c;就返回1&#xff0c;就是找到一个叶子结点&#xff0c;然后访问完每个不为空的结点就行&#xff0c;每次访问都是把当前结点的左/右结点作为新的结点&#xff0c;来判断。 求最大深度&…

为何线程有PID?

在linux下用 top -H -p <pid> 查询某个进程的线程 按理说&#xff0c;都是某个进程下的线程&#xff0c; 应该进程id PID一样啊&#xff0c;但实际却都不一样 实际是被PID的名字给弄混了&#xff0c;线程进程都会有自己的ID&#xff0c;这个ID就叫做PID&#xff0c;P…

关于树和二叉树的一些基本概念,基本名词解释。

二叉树的概念 概念 一棵二叉树是结点的一个有限集合&#xff0c;该集合或者为空&#xff0c;或者是由一个根节点加上两棵别称为左子树和右子树 的二叉树组成。 二叉树的特点&#xff1a; 每个结点最多有两棵子树&#xff0c;即二叉树不存在度大于2的结点。二叉树的子树有左右…

在VI中删除行尾的换行符

在vi中&#xff0c;如果要删除行尾的换行符&#xff0c;可以用如下方法 第一种情况&#xff1a;只删除单行 如有文件如下&#xff1a; [fanzfSWserver ~/tmp]$ cat names.tmp 101 Nate H. 102 John M. 104 Cassy T. 106 Mary L. 107 Isaac …

用c语言构建二叉树(重点)

结点创建 二叉树创建 我们以‘#’为NULL&#xff0c;我们要把输入进来的一个字符串转变为二叉树&#xff0c;所以我们要记住递归的每一步走到数组了哪个位置 所以我们要记住创建过程中用掉的前序个数&#xff0c;并返回&#xff0c;除此之外&#xff0c;还要加上当时的那个结点…

linux 同步IO: sync msync、fsync、fdatasync与 fflush

最近阅读leveldb源码&#xff0c;作为一个保证可靠性的kv数据库其数据与磁盘的交互可谓是极其关键&#xff0c;其中涉及到了不少内存和磁盘同步的操作和策略。为了加深理解&#xff0c;从网上整理了linux池畔同步IO相关的函数&#xff0c;这里做一个罗列和对比。大部分为copy&a…

二叉树的广度优先遍历(层序遍历)

先定义一个二叉树的结点 再创建二叉树&#xff0c;这里就不写了&#xff0c;之前的有创建二叉树的博客。 层序遍历 用到栈的思想&#xff0c; 1 先让根 节点进队列&#xff0c;2 然后读队顶元素&#xff0c;3 让他出队列4 打印它的值5 让队顶元素的左右子树进栈&#xff0…