-
#include <unistd.h>
-
#include <fcntl.h>
-
-
int fcntl(int fd, int cmd, ... /* arg */ );
fcntl主要对打开的文件描述符执行本文以下描述的几类操作;根据cmd参数执行相应操作,cmd在下面描述中列出;
1. 复制文件描述符
F_DUPFD 找出最小的可用的文件描述符或者大于等于arg的文件描述符作为fd的拷贝;
如 fcntl(fd,F_DUPFD,0)等价于 dup(fd);
-
int main(void){
-
int fd=fcntl(STDOUT_FILENO,F_DUPFD,0);
-
if(fd<0){
-
fprintf(stderr,"fcntl dupfd error %d\n",fd);
-
exit(1);
-
}
-
printf("duplicate fd %d\n",fd);
-
-
exit(0);
-
}
2.文件描述符标记位的读取和设置
F_GETFD 读取文件描述符标记,此时arg参数忽略
F_SETFD 设置文件描述符标记,文件描述标记设置位arg;当前只有一个FD_CLOEXEC
3.文件状态标记的读取和设置
F_GETFL 获取文件的访问模式和文件的状态标记,此时arg参数忽略
F_SETFL 将arg设置为文件的访问模式(O_RDONLY, O_WRONLY,O_RDWR)和创建标记(O_CREAT, O_EXCL, O_TRUNC...)
4.咨询锁(Advisory Locking)
F_GETLK F_SETLK F_SETLKW用来获取、释放、测试存在的记录锁(也称为文件片段或文件区域锁),第三个参数lock是一个指针;
F_GETLK 如果试图锁定一个已经被锁定的文件,将会返回-1,并且errno设置为EACESS或者EAGAIN;
F_SETLKW 如果试图锁定一个已经被锁定的文件,调用进程将会阻塞等待,直到锁释放或者被信号中断;
当放置一个“读”锁时,确保文件描述符时打开的;当放置一个“写”锁,确保文件描述符可读可写;
-
struct flock {
-
...
-
short l_type; /* Type of lock: F_RDLCK,
-
F_WRLCK, F_UNLCK */
-
short l_whence; /* How to interpret l_start:
-
SEEK_SET, SEEK_CUR, SEEK_END */
-
off_t l_start; /* Starting offset for lock */
-
off_t l_len; /* Number of bytes to lock */
-
pid_t l_pid; /* PID of process blocking our lock
-
(F_GETLK only) */
-
...
-
};
l_type指定了锁的类型 F_RDLCK , F_WRLCK, F_UNLCK;多个进程能够共享“读”锁(共享锁),但是一次只能由一个进程享有“写”锁(互斥锁);
l_whence 指定了锁定的开始位置
SEEK_SET文件的开头;
SEEK_CUR文件中指针的当前位置;
SEEK_END文件的末尾;
l_start 指定了相对开始位置的偏移位置;
l_len 指定了锁定文件的字节数
l_pid 指定了阻塞当前锁的进程PID;
在设定读写锁时,由于标准库中的读写操作具有缓存,应该直接使用read,write 系统函数;
通常在linux系统中会看到很多以.pid结尾的文件,比如mongodb里面就有一个lock.pid,这个文件就是一个使用以上的锁机制创建的锁文件,主要目的是为了保证daemon程序的单例,即同一个daemon程序一次只能运行一个;当一个daemon开始运行,就会创建一个文件,并锁定,通常该文件的内容时该进程的pid,当在运行该进程时,就会发生错误;因为文件锁机制保证了该daemon的单例性;
下面就通过一个程序来演示fcntl的文件锁机制。
头文件"myfcntl.h"
-
#include <unistd.h>
-
#include <fcntl.h>
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <errno.h>
-
#include <sys/types.h>
-
-
#define error_handle(en,msg) \
-
do{errno=en;perror(msg);exit(EXIT_FAILURE);}while(0)
-
-
int lockfile(int fd){
-
struct flock fl;
-
-
fl.l_type=F_WRLCK;
-
fl.l_start=0;
-
fl.l_whence=SEEK_SET;
-
fl.l_len=0;
-
return(fcntl(fd,F_SETLK,&fl));
-
}
-
~
singlerun.c
-
#include <unistd.h>
-
#include <fcntl.h>
-
#include <stdlib.h>
-
#include <stdio.h>
-
#include <syslog.h>
-
#include <string.h>
-
#include <errno.h>
-
#include <sys/stat.h>
-
-
#define LOCKFILE "/home/yamorn/daemon.pid"
-
#define LOCKMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)
-
-
extern int lockfile(int);
-
-
int already_running(void){
-
int fd;
-
char buf[16];
-
-
fd=open(LOCKFILE,O_RDWR|O_CREAT,LOCKMODE);
-
if(fd<0){
-
syslog(LOG_ERR,"can't open %s: %s",LOCKFILE,strerror(errno));
-
exit(1);
-
}
-
if(lockfile(fd)<0){
-
if(errno==EACCES||errno==EAGAIN){
-
close(fd);
-
return(1);
-
}
-
syslog(LOG_ERR,"can't lock %s: %s",LOCKFILE,strerror(errno));
-
exit(1);
-
}
-
ftruncate(fd,0);
-
sprintf(buf,"%ld",(long)getpid());
-
write(fd,buf,strlen(buf)+1);
-
return(0);
-
}
阅读(798) | 评论(0) | 转发(0) |