fcntl和select函数彻底搞明白第一、fcntl函数详细使用fcntl有强大的功能,它能够复制一个现有的描述符,获得/设置文件描述符标记,获得/设置文件状态标记,获得/设置异步I/O所有权,获得/设置纪录锁。当多个用户共同使用,操作一个文件的情况,Linux通常采用的方法就是给文件上锁,来避免共享资源产生竞争的状态。fcntl文件锁有两种类型:建议性锁和强制性锁建议性锁是这样规定的:每个使用上锁文件的进程都要检查是否有锁存在,当然还得尊重已有的锁。内核和系统总体上都坚持不使用建议性锁,它们依靠程序员遵守这个规定。强制性锁是由内核执行的。当文件被上锁来进行写入操作时,在锁定该文件的进程释放该锁之前,内核会阻止任何对该文件的读或写访问,每次读或写访问都得检查锁是否存在。使用fcntl文件锁进行I/O操作必须小心:进程在开始任何I/O操作前如何去处理锁,在对文件解锁前如何完成所有的操作,是必须考虑的。如果在设置锁之前打开文件,或者读取该锁之后关闭文件,另一个进程就可能在上锁/解锁操作和打开/关闭操作之间的几分之一秒内访问该文件。当一个进程对文件加锁后,无论它是否释放所加的锁,只要文件关闭,内核都会自动释放加在文件上的建议性锁(这也是建议性锁和强制性锁的最大区别),所以不要想设置建议性锁来达到永久不让别的进程访问文件的目的(强制性锁才可以)^_^;强制性锁则对所有进程起作用。可以用fcntl函数改变一个已打开的文件的属性,可以重新设置读、写、追加、非阻塞等标志(这些标志称为FileStatusFlag),而不必重新open文件。#include<unistd.h>#include<fcntl.h>intfcntl(intfd,intcmd);intfcntl(intfd,intcmd,longarg);intfcntl(intfd,intcmd,structflock*lock);这个函数和open一样,也是用可变参数实现的,可变参数的类型和个数取决于前面的cmd参数。文件锁包括了建议性锁和强制性锁。建议性锁要求每个上锁的文件的进程都要检查是否有锁存在,并且尊重已有的锁,在一般情况下,内核和系统都不使用建议性锁。强制性锁是由内核执行的锁,当一个文件被上锁进行读写操作的时候,内核将阻止其他任何文件对其进行读写操作。每次读写操作都要检查是否有锁存在。在Linux中实现上锁的函数有lock()和fcntl()。lock()用于对文件施加建议性锁fcntl()用于对文件施加建议性锁和强制性锁都行。同时还可以对文件某一条纪录进行上锁,也就是记录锁。记录锁分为读取锁(共享锁,它能够使多个进程都能在文件的同一部分建立读取锁)和写入锁(排斥锁,在任何时刻只能有一个进程在文件的某部分建立写入锁。)。fcntl函数原型#include<sys/types.h>#include<unistd.h>#include<fcntl.h>intfcntl(intfd,//文件描述符intcmd,//不同的命令structflock*lock)//设置记录锁的具体状态cmd取值:F_DUPFD复制文件描述符F_GETFD获得fd的close-on-exec标志F_SETFD设置close-on-exec标志F_GETFL获得open设置标志F_SETFL设置lock描述的标志F_GETLK测试该锁是否被另外一把锁排斥F_SETLKW如果存在其他锁,则调用进程睡眠,如果捕捉到信号则睡眠中断F_GETOWN检索收到的SIGIO和SIGURG信号的进程号或者进程组号F_SETOWN设置进程号或进程组号这里的lock结构体如下:structflock{shortl_type;/*F_RDLCK(读取锁),F_WRLCK(写入锁),F_UNLCK(解锁)*/off_tl_start;/*相对偏移量(字节)*/shortl_whence;/*SEEK_SET,SEEK_CUR,SEEK_END*/off_tl_len;/*加锁区域长度*/pid_tl_pid;}成功:0出错:-1提示:如果加锁整个文件通常的方法是将l_start设置为0,l_whence设置为SEEK_SET,l_len设置为0。下面的例子使用F_GETFL和F_SETFL这两种fcntl命令改变STDIN_FILENO的属性上O_NONBLOCK选项,实现非阻塞读终端的功能。用fcntl改变FileStatusFlag#include<unistd.h>#include<fcntl.h>#include<errno.h>#include<string.h>#include<stdlib.h>#defineMSG_TRY"tryagain\n"intmain(void){charbuf[10];intn;intflags;flags=fcntl(STDIN_FILENO,F_GETFL);flags|=O_NONBLOCK;if(fcntl(STDIN_FILENO,F_SETFL,flags)==-1){perror("fcntl");exit(1);}tryagain:n=read(STDIN_FILENO,buf,10);if(n<0){if(errno==EAGAIN)...