文件锁
#include <sys/file.h>
int flock(int fd, int operation);
参数说明:
- LOCK_SH 建立共享锁定。多个进程可同时对同一个文件作共享锁定。
- LOCK_EX 建立互斥锁定。一个文件同时只有一个互斥锁定。
- LOCK_UN 解除文件锁定状态。
- LOCK_NB 无法建立锁定时,此操作可不被阻断,马上返回进程。通常与LOCK_SH或LOCK_EX 做OR(|)组合。
单一文件无法同时建立共享锁定和互斥锁定,而当使用dup()或fork()时文件描述词不会继承此种锁定。
返回值说明:
返回0表示成功,若有错误则返回-1,错误代码存于errno。
lock()会依参数operation所指定的方式对参数fd所指的文件做各种锁定或解除锁定的动作。此函数只能锁定整个文件,无法锁定文件的某一区域。
使用方式:
- flock只要在打开文件后,需要对文件读写之前flock一下就可以了,用完之后再flock一下,前面加锁,后面解锁。
- 进程使用flock尝试锁文件时,如果文件已经被其他进程锁住,进程会被阻塞直到锁被释放掉,或者在调用flock的时候,采用LOCK_NB参数,在尝试锁住该文件的时候,发现已经被其他服务锁住,会返回错误。
- 可调用LOCK_UN参数来释放文件锁,也可以通过关闭fd的方式来释放文件锁(flock的第一个参数是fd),意味着flock会随着进程的关闭而被自动释放掉
测试
测试用例1
进程A:打开要操作的文件,进行加锁,在文件中写入数据,等待键盘输入字符(此时该A进程处于等待状态,立刻运行B进程),键盘输入字符后,发现加锁文件中出现text字符串
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include<sys/file.h>
static const char jsonfile[] = "new.json";
int main()
{
FILE *fp;
char buf[1024] = {0};
char text[] = "this is write test=========\n";
if ((fp = fopen((jsonfile), "aw+")) == NULL)
return 0;
if (0 == flock(fileno(fp), LOCK_EX))
{
printf("lock...\n");
fseek(fp, 0, SEEK_END);
fwrite(text, strlen(text), 1, fp);
getchar();
fclose(fp);
flock(fileno(fp), LOCK_UN);
}
else
{
printf("lock failed\n");
}
return 0;
}
进程B:打开要操作的文件,进行加锁并设置立即返回参数,如果返回值是-1,说明文件已被其他进程占用,然后进行持续加锁,直到成功加锁(此时刻是由于A进程在键盘中输入了字符,释放了锁)睡眠2s后退出加锁持续,对文件进行数据追加写入操作,发现在A进程中的text字段后面出现了该B进程写入的数据,即可说明文件锁生效,能成功保护文件被两个进程同时读写操作
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/file.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
static const char jsonfile[] = "new.json";
int main()
{
char texts[] = "-----------this is read test\n";
FILE *fp;
if ((fp = fopen(jsonfile, "aw+")) == 0)
printf("can't open file!\n");
else
{
printf("open file success!\n");//LOCK_NB 无法建立锁定时,此操作可不被阻断,马上返回进程
int i = flock(fileno(fp), LOCK_SH | LOCK_NB); // 加锁以判断文件是否已经被加锁了,单一文件无法同时建立共享锁定和互斥锁定
printf("%d\n", i); //-1表示文件被其他进程加锁,0表示文件被该进程加锁
if (i == -1)
{
printf("lock by others ...\n");
while (1)
{
i = flock(fileno(fp), LOCK_SH | LOCK_NB);
if (i == 0)
{
sleep(2);
printf("lock file success!!!!!!!!!!!\n");
break;
}
}
}
flock(fileno(fp), LOCK_UN);
fwrite(texts, strlen(texts), 1, fp);
}
fclose(fp);
return 0;
}
被两个进程同时操作的new.json数据文件内容如下:
this is write test=========
-----------this is read test
第二行数据在第一行数据出现2S后才出现
结果说明:验证了flock函数在多进程操作同一个文件时对文件的保护作用
测试用例2
多进程同时操作同一个文件无延时循环读写测试
进程A:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include<sys/file.h>
static const char jsonfile[] = "new.json";
int main()
{
char text[] = "this is write test=========\n";
while (1)
{
FILE *fp;
if ((fp = fopen((jsonfile), "aw+")) == NULL)
return 0;
if (0 == flock(fileno(fp), LOCK_EX))
{
printf("lock...\n");
fseek(fp, 0, SEEK_END);
fwrite(text, strlen(text), 1, fp);
//getchar();
fclose(fp);
flock(fileno(fp), LOCK_UN);
}
else
{
printf("lock failed\n");
}
}
//usleep(500);
return 0;
}
进程B:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include<sys/file.h>
static const char jsonfile[] = "new.json";
int main()
{
char text[] = "-----------this is read test\n";
while (1)
{
FILE *fp;
if ((fp = fopen((jsonfile), "aw+")) == NULL)
return 0;
if (0 == flock(fileno(fp), LOCK_EX))
{
printf("lock...\n");
fseek(fp, 0, SEEK_END);
fwrite(text, strlen(text), 1, fp);
//getchar();
fclose(fp);
flock(fileno(fp), LOCK_UN);
}
else
{
printf("lock failed\n");
}
}
//usleep(500);
return 0;
}
经过测试两个进程在一个文件中连续不断写入数据,写入数据到该文件达到100M后停止写入,然后分析文件中的数据
分析写入数据正确性的程序:
#include <stdio.h>
#include <string.h>
static const char jsonfile[] = "/home/nfs/new.json";
char texts[] = "this is write test=========";
char text[] = "-----------this is read test";
int main()
{
char buff[1024] = {0};
int bufflinenum = 0, num = 0;
FILE *fp;
if ((fp = fopen(jsonfile, "r+")) == 0)
printf("can't open file!\n");
while (!feof(fp))
{
if (fgets(buff, sizeof(buff), fp) != NULL)
{
bufflinenum++;
if((strncmp(buff, text, strlen(buff)-1) != 0 ) && strncmp(buff, texts,strlen(buff)-1) != 0 )
{
num++;
printf("出错行内容:\n%s", buff);
}
else
{
//printf("%s", buff);
}
}
}
printf("文件总行数:%d\n出错行数:%d\n", bufflinenum, num);
return 0;
}
分析结果: