Linux应用程序之文件锁操作

来源:岁月联盟 编辑:exp 时间:2012-03-06

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的专栏