发布时间:2014-09-05 16:28:04作者:知识屋
Linux下文件锁操作主要是通过以下两个API接口来完成的。
#include <sys/file.h>
int flock(int fd, int operation);
或者
#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);
注:前者主要用于对整个文件的锁操作,后者可以对文件的部分内容进行锁操作。
Linux应用程序编程时应该注意以下几点:
1)文件锁是针对整个文件还是文件的部分内容。
2)进程级文件句柄关闭将会导致文件锁释放。
3)文件内容修改需要注意到glibc的缓冲机制,及时同步数据。
4)flock锁inode,fcntl锁文件描述符,因此flock不支持NFS,兼容性需要注意。
这里将给出进程级和线程级文件锁demo code供参考。
进程级文件锁demo:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#define TEST_FOPEN
int main(int argc, char *argv[])
{
/* l_type l_whence l_start l_len l_pid */
struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0 };
int fd;
#ifdef TEST_FOPEN
FILE *file = NULL;
#endif /* TEST_FOPEN */
fl.l_pid = getpid();
if (argc > 1)
fl.l_type = F_RDLCK;
while(1)
{
#ifdef TEST_FOPEN
if ((file = fopen("lockdemo.c", "rw+")) == NULL) {
perror("fopen");
exit(1);
}
#else
if ((fd = open("lockdemo.c", O_RDWR)) == -1) {
perror("open");
exit(1);
}
#endif /* TEST_FOPEN */
printf("Press <RETURN> to try to get lock: ");
getchar();
printf("Trying to get lock...");
#ifdef TEST_FOPEN
fd = fileno(file);
#endif /* TEST_FOPEN */
fl.l_type = F_WRLCK; /* set to lock same region */
if (fcntl(fd, F_SETLKW, &fl) == -1) {
perror("fcntl");
exit(1);
}
printf("got lock/n");
printf("Press <RETURN> to release lock: ");
getchar();
fl.l_type = F_UNLCK; /* set to unlock same region */
if (fcntl(fd, F_SETLK, &fl) == -1) {
perror("fcntl");
exit(1);
}
printf("Unlocked./n");
#ifdef TEST_FOPEN
fclose(file);
#else
close(fd);
#endif /* TEST_FOPEN */
}
return 0;
}
运行结果:
线程级文件锁demo:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#define TEST_FOPEN
#define TEST_FLOCK
void* thread_flock(void* ptr)
{
/* l_type l_whence l_start l_len l_pid */
struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0 };
int fd;
int ith = *((int *)ptr);
#ifdef TEST_FOPEN
FILE *file = NULL;
#endif /* TEST_FOPEN */
fl.l_pid = getpid();
while(1)
{
#ifdef TEST_FOPEN
if ((file = fopen("lockdemo.c", "rw+")) == NULL) {
perror("fopen");
exit(1);
}
#else
if ((fd = open("lockdemo.c", O_RDWR)) == -1) {
perror("open");
exit(1);
}
#endif /* TEST_FOPEN */
#ifdef TEST_FOPEN
fd = fileno(file);
#endif /* TEST_FOPEN */
#ifdef TEST_FLOCK
flock(fd, LOCK_EX);
#else
fl.l_type = F_WRLCK; /* set to lock same region */
if (fcntl(fd, F_SETLKW, &fl) == -1) {
perror("fcntl");
exit(1);
}
#endif /* TEST_FLOCK */
printf("[%d] %d --> got lock/n", ith, fd);
sleep(ith);
#ifdef TEST_FLOCK
flock(fd, LOCK_UN);
#else
fl.l_type = F_UNLCK; /* set to unlock same region */
if (fcntl(fd, F_SETLKW, &fl) == -1) {
perror("fcntl");
exit(1);
}
#endif /* TEST_FLOCK */
printf("[%d] %d--> Unlocked./n", ith, fd);
#ifdef TEST_FOPEN
fclose(file);
#else
close(fd);
#endif /* TEST_FOPEN */
sleep(2);
}
}
int main(int argc, char *argv[])
{
int time1, time2;
pthread_t pid1,pid2;
time1 = 1;
pthread_create(&pid1, NULL, &thread_flock, &time1);
time2 = 3;
pthread_create(&pid2, NULL, &thread_flock, &time2);
while(1)
sleep(10);
return 0;
}
运行结果:
参考资料:
【1】Linux man pages
【2】fcntl() for thread or process synchronization?
【3】How to lock files using fcntl() and to work between threads of the same process
【4】fcntl+pthread_rwlock制作的支持多进程多线程混合的互斥锁
【5】flock不支持NFS
【6】Re: Linux, fcntl vs flock and pthreads
摘自 lida2003的专栏
linux一键安装web环境全攻略 在linux系统中怎么一键安装web环境方法
Linux网络基本网络配置方法介绍 如何配置Linux系统的网络方法
Linux下DNS服务器搭建详解 Linux下搭建DNS服务器和配置文件
对Linux进行详细的性能监控的方法 Linux 系统性能监控命令详解
linux系统root密码忘了怎么办 linux忘记root密码后找回密码的方法
Linux基本命令有哪些 Linux系统常用操作命令有哪些
Linux必学的网络操作命令 linux网络操作相关命令汇总
linux系统从入侵到提权的详细过程 linux入侵提权服务器方法技巧
linux系统怎么用命令切换用户登录 Linux切换用户的命令是什么
在linux中添加普通新用户登录 如何在Linux中添加一个新的用户
2012-07-10
CentOS 6.3安装(详细图解教程)
Linux怎么查看网卡驱动?Linux下查看网卡的驱动程序
centos修改主机名命令
Ubuntu或UbuntuKyKin14.04Unity桌面风格与Gnome桌面风格的切换
FEDORA 17中设置TIGERVNC远程访问
StartOS 5.0相关介绍,新型的Linux系统!
解决vSphere Client登录linux版vCenter失败
LINUX最新提权 Exploits Linux Kernel <= 2.6.37
nginx在网站中的7层转发功能