Linux应用程序之文件锁操作

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

你可能感兴趣的:(thread,linux,struct,File,null,pthreads)