http://blog.csdn.net/lida2003/article/details/7267226
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;
- }
运行结果:
参考资料:
【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