文件锁
文件锁:锁住整个文件或者锁住文件的一部分。
文件为什么要锁?
比如下载文件,一般是用多线程来实现的,那怎么才能确定每个线程操作的那一部分文件区域是被独立控制的,而没有同时被别人使用呢,我就可以使用文件锁。
下面的这些函数都能实现锁文件或者锁住文件的一部分。
fcntl();
lockf();
flock();
通过某个文件描述符对文件加锁反应到的是inode这个层面,而不是当前文件这个层面。因此指向这个文件的文件描述符是有可能对它造成意外解锁的。
inode结点可以看下链接: https://blog.csdn.net/xuechanba/article/details/119320211.
这里使用 lockf 这个函数来实现文件锁。
#include <unistd.h>
int lockf(int fd, int cmd, off_t len);
我要对它实现的cmd命令:
F_LOCK
F_LOCK为文件指定的部分设置排他锁。如果这个部分已经被锁定,调用将阻塞,直到前一个锁被释放。如果此节与之前的锁定节重叠,则将两者合并。当持有锁的进程关闭文件的某些文件描述符时,文件锁就被释放。子进程不会继承这些锁。
F_ULOCK
Unlock the indicated(指定的) section of the file.
看第三个参数len
and if len is zero, the section extends from the current file position to infinity, encompassing the present and future end-of-file positions.
如果len为0,该section将从当前文件位置扩展到无限,包括当前和将来的文件结束位置。
看返回值
RETURN VALUE
On success, zero is returned. On error, -1 is returned, and errno is set appropriately.
需求:
文件中的内容为1,创建20个线程,每个线程都对读到的内容进行加1操作。在操作过程中,为了避免竞争,使用文件锁。
程序:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#define PROCNUM 20
#define FNAME "/work/thread_code/filelock/test"
#define LINESIZE 1024
void func_add()
{
int fd;
FILE *fp;
char linebuf[LINESIZE];
fp = fopen(FNAME,"r+");
if(fp == NULL)
{
perror("fopen()");
exit(1);
}
//将fp流中的文件描述符fd给挑出来
//file流中一定有一个文件描述符
fd = fileno(fp);
//锁多长不确定,因为有时候文件长度是会变化的
lockf(fd,F_LOCK,0);
fgets(linebuf,LINESIZE,fp);
fseek(fp,0,SEEK_SET);//文件内指针定位
//用来放大故障
sleep(1);
//加1再写回去
fprintf(fp,"%d\n",atoi(linebuf)+1);
//因为文件是全缓存模式,而fprintf是行缓存模式
//有可能出现写不进去的情况,所以要加一个刷新流的操作
fflush(fp);
//防止其他指向该文件的文件描述符意外解锁
lockf(fd,F_ULOCK,0);
fclose(fp);
return;
}
int main()
{
pid_t pid;
int i;
for(i=0;i<PROCNUM;i++)
{
pid = fork();
if(pid < 0)
{
perror("fork()");
exit(1);
}
if(pid == 0)
{
func_add();
exit(0);
}
}
for(i=0;i<PROCNUM;i++)
{
wait(NULL);
}
return 0;
}
运行程序,等待超过20秒之后。