fcntl函数之文件锁 F_SETLKW
F_SETLK与F_SETLKW的区别:
F_SETLK设的锁遇到锁被其他进程占用时,会立刻停止进程。
F_SETLKW上锁是阻塞方式。设置的锁因为其他锁而被阻止设置时,该命令会等待相冲突的锁被释放。
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
/**
*
*./myfcntl content type
struct flock {
...
short l_type; 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 (set by F_GETLK and F_OFD_GETLK)
...
};
*
*/
int lock_reg(int fd, int cmd, short lock_type, short lock_whence, off_t lock_start, off_t lock_len)
{
struct flock lock;
lock.l_type = lock_type;
lock.l_whence = lock_whence;
lock.l_start = lock_start;
lock.l_len = lock_len;
lock.l_pid = getpid();
if (fcntl(fd, cmd, &lock) < 0) {
if (errno == EACCES || errno == EAGAIN ) {
printf("file lock by other processes.\n");
return -1;
}
printf("lock file fail.\n");
return -1;
}
if (lock_type == F_WRLCK) {
printf("lock by %d.\n", getpid());
} else if (lock_type == F_UNLCK) {
printf("unlock by %d.\n", getpid());
}
return 0;
}
int reg_lock(int fd)
{
return lock_reg(fd, F_SETLK, F_WRLCK, 0, SEEK_SET, 0);
}
int reg_unlock(int fd)
{
return lock_reg(fd, F_SETLK, F_UNLCK, 0, SEEK_SET, 0);
}
int reg_lockw(int fd)
{
return lock_reg(fd, F_SETLKW, F_WRLCK, 0, SEEK_SET, 0);
}
int reg_unlockw(int fd)
{
return lock_reg(fd, F_SETLKW, F_UNLCK, 0, SEEK_SET, 0);
}
/*
*
*.myfcntl AAAAAA
*/
int main(int argv, char *argc[])
{
char *buf;
int i;
int ret;
int fd;
if (argv < 2) {
printf("argc error!\n");
return -1;
}
fd = open("processes.txt", O_CREAT|O_RDWR|O_APPEND, 777);
ret = reg_lockw(fd);
if (ret !=0 ) {
return -1;
}
sleep(5);
buf = argc[1];
i = 0;
while (i < strlen(buf)) {
if (write(fd, buf+i, sizeof(char)) < sizeof(char)) {
printf("printf out error!\n");
return -1;
}
printf(" %c:out by pid %d.\n", buf[i], getpid());
i++;
sleep(1);
}
ret = reg_unlockw(fd);
if (ret !=0 ) {
return -1;
}
close(fd);
return 0;
}
同时运行两个进程,第二个被阻塞不退出,直到第一个进程解锁,第二个进程再上锁。
#结果
lock by 18687.
B:out by pid 18687.
B:out by pid 18687.
B:out by pid 18687.
B:out by pid 18687.
B:out by pid 18687.
B:out by pid 18687.
B:out by pid 18687.
unlock by 18687.
lock by 18686.
A:out by pid 18686.
A:out by pid 18686.
A:out by pid 18686.
A:out by pid 18686.
A:out by pid 18686.
A:out by pid 18686.
A:out by pid 18686.
unlock by 18686.
fcntl分为建议锁和强制性锁,默认是建议锁模式,该模式下,一个文件被一个进程锁住后,第二个进程是能直接往这个文件写数据的。建议每次输入数据前都有个上锁操作。