1.struct flock介绍
结构体描述
锁类型: F_RDLCK(读共享锁), F_WRLCK(写互斥锁),和F_UNLCK(对一个区域解锁)
锁开始: 锁位置(l_whence),相对于l_whence要锁或者解锁的区域开始位置(l_start)
锁长度: 要锁的长度,字节计数(l_len)
锁拥有者:记录锁的拥有进程ID,这个进程可以阻塞当前进程,仅F_GETLK形式返回
struct flock
{
short l_type; /*F_RDLCK, F_WRLCK, or F_UNLCK*/
off_t l_start; /*相对于l_whence的偏移值,字节为单位*/
short l_whence; /*从哪里开始:SEEK_SET, SEEK_CUR, or SEEK_END*/
off_t l_len; /*长度, 字节为单位; 0 意味着缩到文件结尾*/
pid_t l_pid; /*returned with F_GETLK*/
};
2.fcntl函数介绍
fcntl系统调用可以用来对已打开的文件描述符进行各种控制操作以改变已打开文件的的各种属性
原型:int fcntl(int fd, int cmd ,struct flock* lock);
参数:
fd是要锁定的文件描述符
对于cmd参数,可以使用的有: F_GETLK, F_SETLK(较多使用)or F_SETLKW
第三个参数(flockptr),指向一个flock结构指针
返回值:如果出错,返回-1,错误原因保存在错误码errno中,如果成功则返回某个其他值
注意:
1)fcntl函数添加锁失败:errno=9, Bad file descriptor
原因之一:打开文件方式为只读打开,却想添加写文件锁导致
2)fcntl函数造成互斥的测试:一般是两个线程之间测试(一个线程上锁,另一个尝试去写)
3)fcntl函数文件锁:两个线程之间同时上读锁不造成互斥,可以同时读取访问
4)fcntl函数文件锁:两个不同线程对同一资源的文件描述符可以不一致(和资源的文件描述符是否相同无关)
//根据锁类型封装函数
#define read_lock(fd, offset, whence, len) \
lock_reg((fd), F_SETLK, F_RDLCK, (offset), (whence), (len))
#define readw_lock(fd, offset, whence, len) \
lock_reg((fd), F_SETLKW, F_RDLCK, (offset), (whence), (len))
#define write_lock(fd, offset, whence, len) \
lock_reg((fd), F_SETLK, F_WRLCK, (offset), (whence), (len))
#define writew_lock(fd, offset, whence, len) \
lock_reg((fd), F_SETLKW, F_WRLCK, (offset), (whence), (len))
#define un_lock(fd, offset, whence, len) \
lock_reg((fd), F_SETLK, F_UNLCK, (offset), (whence), (len))
int lock_reg(int fd, int cmd, int type, off_t offset, int whence, off_t len){
struct flock lock;
lock.l_type = type;
lock.l_start = offset;
lock.l_whence = whence;
lock.l_len = len;
return(fcntl(fd, cmd, &lock));
}
//核心代码
static int function_write() //写文件锁
{
/* 写文件前设置写锁 */
if(write_lock(fileno(host_fp), 0, SEEK_SET, 0) == -1)
{
fprintf(stderr,"%s: write_lock fail: %s, sleep 5s, try again.\n", __FUNCTION__, strerror(errno));
sleep(5);
write_lock(fileno(host_fp), 0, SEEK_SET, 0);
}
/*
写操作
...
...
...
*/
/* 写完后要释放锁 */
if(un_lock(fileno(host_fp), 0, SEEK_SET, 0) == -1)
{
fprintf(stderr,"%s: unlock fail: %s, sleep 1s, try again.\n", __FUNCTION__, strerror(errno));
sleep(1);
un_lock(fileno(host_fp), 0, SEEK_SET, 0);
}
}
static int function_read() //读文件锁
{
if(read_lock(fileno(fp), 0, SEEK_SET, 0) == -1)
{
fprintf(stderr,"%s: read_lock fail: %s. sleep 5s, try again.\n", __FUNCTION__, strerror(errno));
sleep(5);
read_lock(fileno(fp), 0, SEEK_SET, 0);
}
/*
读文件操作
...
...
...
*/
if(un_lock(fileno(fp), 0, SEEK_SET, 0) == -1)
{
fprintf(stderr,"%s: unlock fail: %s. sleep 1s, try again.\n", __FUNCTION__, strerror(errno));
sleep(1);
un_lock(fileno(fp), 0, SEEK_SET, 0);
}
}