网站建设多少,电脑机箱定制网站,做微信活动是做网站还是做小程序好,效果图网址什么是文件锁#xff1f;
即锁住文件#xff0c;不让其他程序对文件做修改#xff01; 为什么要锁住文件#xff1f;
案例#xff0c;有两个程序#xff0c;都对一个文件做写入操作。
#include unistd.h
#include stdio.h
#include stdlib.h
…什么是文件锁
即锁住文件不让其他程序对文件做修改 为什么要锁住文件
案例有两个程序都对一个文件做写入操作。
#include unistd.h
#include stdio.h
#include stdlib.h
#include errno.h
#include string.h#define FILE_NAME flock_demo.txtint main(void) {int fd -1;char buf[64] hello, data one!\n; // 程序1写入文件内容//char buf[64] hi, data two!\n; // 程序2写入文件内容fd open(FILE_NAME, O_RDWR|O_CREAT, 00666);if (fd 0) {fprintf(stderr, open file %s failed! reason: %s\n, FILE_NAME, strerror(errno));exit(-1);}int ret write(fd, buf, sizeof(buf));if (-1 ret) {fprintf(stderr, write failed. reason: %s\n, strerror(errno));exit(-2);}printf(write successful! start sleep 10s...\n);sleep(10);close(fd);return 0;
}
程序1对文件flock_demo.txt写入hello, data one!
程序2对文件flock_demo.txt写入hi, data two!
然后都睡眠10秒后才调用close函数关闭文件然后程序结束
首先运行程序1然后运行程序2来看看运行后的文件结果 根据图片测试结果可知程序1先将hello, data one!写入文件然后睡眠10秒钟然后程序2将hi, data two!写入文件将程序1写入的内容给覆盖掉了然后睡眠10秒10秒后程序1执行close函数关闭文件退出程序10秒后程序2执行close函数关闭文件退出程序。
但此时文件内容保存的是程序2写入的内容程序1的调用者肯定就会很纳闷了为什么我调用程序应该要写入hello, data one!才对它为什么写入了hi, data two!呢
如果此时程序1执行一次而程序二不执行那么程序1就可以正常将hello, data one!写入到文件中去那么程序1的调用就很懵逼了百思不得其解。。。 基于以上情况我们操作文件前需要使用文件锁 #include unistd.h #include fcntl.h
int fcntl (int fd, int cmd, ... /* arg */ );
描述文件上锁、解锁等。 fd: 文件描述符
cmd 取值 F_GETLK, F_SETLK 和 F_SETLKW分别表示获取锁、设置锁和同步设置锁.
返回值 成功 返回 0或者返回F_DUPFD、F_GETFD、F_GETFL、F_GETLEASE、F_GETOWN、F_GETSIG、F_GETPIPE_SZ对于一个成功的调用返回值取决于操作 失败 返回 -1并且设置错误编号 errno 可用( strerror(errno) ) 查看. 文件锁的表示
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 以文件结尾为锁定的起始位置。 // struct flock 结构体说明 struct flock { short l_type; /*F_RDLCK, F_WRLCK, or F_UNLCK */ off_t l_start; /*offset in bytes, relative to l_whence */ short l_whence; /*SEEK_SET, SEEK_CUR, or SEEK_END */ off_t l_len; /*length, in bytes; 0 means lock to EOF */ pid_t l_pid; /*returned with F_GETLK */ }; l_type: 第一个成员是加锁的类型只读锁读写锁或是解锁。 l_start和l_whence: 用来指明加锁部分的开始位置。 l_len: 是加锁的长度。设0表示对整个文件加锁。 l_pid: 是加锁进程的进程id。 举例 我们现在需要把一个文件的前三个字节加读锁则该结构体的l_typeF_RDLCK, l_start0, l_whenceSEEK_SET, l_len3, l_pid-1然后调用fcntl函数时 cmd参数设F_SETLK. 1. 文件上锁
struct flock fflock;
memset(fflock, 0, sizeof(struct flock));// 上锁
fflock.l_type F_WRLCK; /* 写锁 */
//fflock.l_type F_RDLCK; /* 读锁 */fflock.l_whence SEEK_SET;
fflock.l_start 0;
fflock.l_len 0; // 为0锁整个文件
fflock.l_pid -1;// 上锁或解锁判断是否成功
//if (fcntl(fd, F_SETLKW, fflock) 0) {
if (fcntl(fd, F_SETLK, fflock) 0) {fprintf(stderr, set file lock failed! reason: %s\n, strerror(errno));return -1;
}
2. 文件解锁
struct flock fflock;
memset(fflock, 0, sizeof(struct flock));fflock.l_type F_UNLCK; // 解锁
fflock.l_whence SEEK_SET;
fflock.l_start 0;
fflock.l_len 0; // 为0解锁整个文件
fflock.l_pid -1;// 上锁或解锁判断是否成功
//if (fcntl(fd, F_SETLKW, fflock) 0) {
if (fcntl(fd, F_SETLK, fflock) 0) {fprintf(stderr, set file lock failed! reason: %s\n, strerror(errno));return -1;
}
3. 获取文件是否上锁
struct flock fflock;
memset(fflock, 0, sizeof(struct flock));// 获取当前文件是否已经上锁
int ret fcntl(fd, F_GETLK, fflock); // F_GETLK
if (-1 ret) {fprintf(stderr, fcntl get lock failed! reason: %s\n, strerror(errno));return -1;
}// 文件已上锁
if (fflock.l_type ! F_UNLCK) {if (fflock.l_type F_RDLCK) { // 文件已上读锁printf(flock has been set to read lock by %d\n, fflock.l_pid);// return; } else if (fflock.l_type F_WRLCK) { // 文件已上写锁printf(flock has been set to write lock by %d\n, fflock.l_pid);// return;}return -1;
}例
#include unistd.h
#include fcntl.h // file lock
#include stdio.h
#include stdlib.h
#include errno.h
#include string.h#define FILE_NAME flock_demo.txtint flock_set(int fd, int type) {// 获取当前进程idprintf(pid %d come in.\n, getpid());struct flock fflock;memset(fflock, 0, sizeof(struct flock));// 获取当前文件是否已经上锁int ret fcntl(fd, F_GETLK, fflock);if (-1 ret) {fprintf(stderr, fcntl get lock failed! reason: %s\n, strerror(errno));return -1;}// 文件已上锁if (fflock.l_type ! F_UNLCK) {if (fflock.l_type F_RDLCK) {printf(flock has been set to read lock by %d\n, fflock.l_pid);} else if (fflock.l_type F_WRLCK) {printf(flock has been set to write lock by %d\n, fflock.l_pid);}return -1;}// lock filefflock.l_type type;fflock.l_whence SEEK_SET;fflock.l_start 0;fflock.l_len 0;fflock.l_pid -1;// 上锁或解锁判断是否成功//if (fcntl(fd, F_SETLKW, fflock) 0) {if (fcntl(fd, F_SETLK, fflock) 0) {fprintf(stderr, set file lock failed! reason: %s\n, strerror(errno));return -1;}switch(fflock.l_type) {case F_RDLCK: {printf(read lock is set by %d\n, getpid());}break;case F_WRLCK: {printf(write lock is set by %d\n, getpid());}break;case F_UNLCK: {printf(lock is released by %d\n, getpid());}break;default:break;}printf(Process pid %d out.\n, getpid());return 0;
}int main(void) {int fd -1;fd open(FILE_NAME, O_RDWR|O_CREAT, 00666);if (fd 0) {fprintf(stderr, open file %s failed! reason: %s\n, FILE_NAME, strerror(errno));exit(-1);}// 1.F_WRLCKint ret flock_set(fd, F_WRLCK); // 写锁//int ret flock_set(fd, F_WRLCK); // 读锁if (-1 ! ret) {getchar();// 2.F_UNLCKflock_set(fd, F_UNLCK);getchar();}close(fd);return 0;
}用以上的代码编译一个读锁程序编译一个写锁程序
main函数中替换以下代码进行编译
int ret flock_set(fd, F_WRLCK); // 写锁 int ret flock_set(fd, F_WRLCK); // 读锁
gcc file_lock.c -o file_w_lock
gcc file_lock.c -o file_r_lock1. 设置锁使用F_SETLK 情况一读锁 和 读锁 结论可以看出两个程序都可以对文件进行加读锁 情况二读锁 和 写锁 结论当文件上读锁后就无法再给文件上写锁且也无法检测处文件上锁状态
即(./file_w_lock)执行代码 int ret fcntl(fd, F_GETLK, fflock); 后其 fflock.l_type ! F_UNLCK 所以没法做中断操作下面再对文件进行上锁操作就函数返回-1了 情况三写锁 和 读锁 结论文件上写锁后再给文件上读锁可以被检测出来文件已经上锁了程序就返回结束了 情况四写锁 和 写锁 结论文件上写锁后再给文件上写锁可以被检测出来文件已经上锁了程序就返回结束了 2. 设置锁使用F_SETLKW
使用F_SETLKW会有等待阻塞的情况 情况一读锁 和 读锁 结论可以看出两个程序都可以对文件进行加读锁 情况二读锁 和 写锁 先给文件上读锁再个文件上写锁此时上写锁程序在获取文件的上锁状态时被阻塞在此等待 当我们在程序1那里按下回车键后对文件解锁右边程序就可以正常对文件上写锁了否则会一直阻塞。。。 情况三写锁 和 读锁 文件上写锁后再给文件上读锁可以被检测出来文件已经上写锁了程序就返回结束了 情况四写锁 和 写锁 结论文件上写锁后再给文件上写锁可以被检测出来文件已经上写锁了程序就返回结束了 3. 其他情况
这里还有另一种情况就是程序1对文件上锁程序2没有对文件上锁然后对文件做写入操作
程序1还是上面的程序代码
程序2代码如下
#include unistd.h
#include stdio.h
#include stdlib.h
#include errno.h
#include string.h
#include fcntl.h#define FILE_NAME flock_demo.txtint main(void) {int fd -1;char buf[64] write file data...\n;fd open(FILE_NAME, O_RDWR|O_CREAT, 00666);if (fd 0) {fprintf(stderr, open file %s failed! reason: %s\n, FILE_NAME, strerror(errno));exit(-1);}int ret write(fd, buf, sizeof(buf));if (-1 ret) {fprintf(stderr, write failed. reason: %s\n, strerror(errno));exit(-2);}printf(write successful!\n);close(fd);return 0;
}
gcc file_write.c -o file_write
文件上读锁 程序1给文件上读锁后程序2依然可以 对文件做写入操作 文件上写锁 程序1给文件上写锁后程序2依然可以对文件做写入操作 结论 由以上两个测试可知给文件上锁仅仅对相应也给文件上锁的程序可以限制对于没有对文件上锁的程序无任何限制 所以在开发中就得做出规定大家对文件操作时都得对文件上锁后再进行操作 总结 文件上锁的几种情况已经列举出来了使用时注意一下就行