fcutl函数簇详解
副标题#e#
成果描写:按照文件描写词来操纵文件的特性。
#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
#p#副标题#e#
可变动的几个符号如下面的描写:
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。
#p#分页标题#e#
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不能共存。
#p#分页标题#e#
下面的例子利用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://yiluohuanghun.blog.51cto.com/3407300/1182262