文件锁的方法:
fcntl()
lockf()
flock()
NAME
lockf - apply, test or remove a POSIX lock on an open file
SYNOPSIS
#include <unistd.h>
/*
fd:需要锁的目标文件
len: 要锁多长,0表示 文件有多长 锁多长,即加锁到文件末端,就算文件加长 也会随之锁上
cmd :实现的命令
F_LOCK 解锁,阻塞式加锁
F_TLOCK 尝试加锁,非阻塞式加锁
F_ULOCK 解锁
F_TEST 测试有没有锁
*/
int lockf(int fd, int cmd, off_t len);
注意:
给一个文件加锁,参数指定fd,通过文件描述符给文件加锁,加锁是加到了文件本身,即inode层面,并不是每个fd所对应的文件属性结构体。注意:当一个进程打开两次同一个文件的时候,如图中所用的第一个和第三个,指向不同的文件属性结构体,但是都是指向同一个 inode文件,这种情况 如果一个加锁后,另一个执行close()文件,会造成加锁的文件被意外解锁。
实验:多进程并发,实现20个进程操作同一个文件,每个进程打开+1 。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <unistd.h>
#define PROCNUM 20
#define FNAME "/home/mhr/Desktop/xitongbiancheng/super_io/out"
#define LINESIZE 1024
static void func_add(void)
{
FILE *fp;
int fd;
char linebuf[LINESIZE];
fp = fopen(FNAME,"r+");
if(fp == NULL)
{
perror("fopen()");
exit(1);
}
fd = fileno(fp);//返回文件描述符
//if(fd < 0)
//上锁,加锁到文件末端
lockf(fd,F_LOCK,0);
fgets(linebuf,LINESIZE,fp);
fseek(fp,0,SEEK_SET);
//sleep(1);
//文件的全缓冲,而fprintf是航缓冲,所以解锁前没有close() 写操作就不能将数据写到文件中,需要ffllush()刷新流
fprintf(fp,"%d\n",atoi(linebuf)+1);
fflush(fp);//刷新
//解锁
lockf(fd,F_ULOCK,0);
//解锁后 close() 防止意外解锁
fclose(fp);
return;
}
int main()
{
int i,err;
pid_t pid;
for(i = 0; i < PROCNUM; i++)
{
pid = fork();//创建20个子进程
if(pid < 0)
{
perror("fork()");
exit(1);
}
if(pid == 0)//Child
{
func_add();
exit(0);//子进程操作后就结束
}
}
for(i = 0;i < PROCNUM; i++)
{
wait(NULL);//父进程收尸
}
exit(0);
}