linux基础之文件锁,读写锁相关

在看建议锁和强制锁时看到的一个帖子。主要问题是,程序运行理想效果是通过创建99个子进程,写入文本100*1000个数。但运行时会随机的少写十几个二十个数。源码如下:

#include <stdio.h>
#include <fcntl.h>

int main()
{
struct flock stF;
int i,n,fd,pid;

fd=open("./output.txt",O_RDWR|O_CREAT);

for(i=0;i<99;i++)
{
        pid=fork();

        if(pid==-1)
        {
                perror("fork:");
        }
        else if( pid > 0 )
        {
                break;
        }
}

stF.l_type=F_WRLCK;
stF.l_start=0;
stF.l_whence=SEEK_SET;
stF.l_len=0;

for(i=0;i<999;i++)
{
        if(fcntl(fd,F_SETLKW,&stF)==-1)
        {
                perror("lock:");
        }

        lseek(fd,0,SEEK_END);
        if(write(fd,"1",1)!=1)
        {
                perror("write:");
        }

        stF.l_type=F_UNLCK;
        if(fcntl(fd,F_SETLKW,&stF)==-1)
        {
                perror("unlock:");
        }
}

close(fd);
}

在查看每次写入数据和pid时,发现数据都会出错。应该是lseek()与fcntl()之间的,还有锁的问题。


很简单,问题在于进程调度,多进程写入同一个文件时存在竞争条件,而lseek和write组合在一起不是原子操作
问题代码:
lseek(fd,0,SEEK_END); // 如果系统刚好把进程挂起在这里,下次进程调度重新运行时将覆盖掉其它进程在此期间向文件写入的数据
if(write(fd,"1",1)!=1)
解决办法很简单,不用lseek调用,直接

问题代码:
lseek(fd,0,SEEK_END); // 如果系统刚好把进程挂起在这里,下次进程调度重新运行时将覆盖掉其它进程在此期间向文件写入的数据
if(write(fd,"1",1)!=1)
解决办法很简单,不用lseek调用,直接

fd = open("./output.txt", O_RDWR | O_CREAT | O_APPEND)


具体原因希望有大侠能解惑啊。对内核运行什么的还不是很了解。


修改方法有如下两种:

一:在打开文件时设置为在每次写之前,都讲标志位移动到文件的末端,而不用lseek()

#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>

int main()
{
struct flock stF;
struct stat stat;
int i,n,fd,pid;

//fd=open("./output.txt",O_RDWR|O_CREAT);
fd=open("./output.txt",O_RDWR|O_CREAT|O_APPEND);

for(i=0;i<99;i++)
{
        pid=fork();

        if(pid==-1)
        {
                perror("fork:");
        }
        else if( pid > 0 )
        {
                break;
        }
}

stF.l_type=F_WRLCK;
stF.l_start=0;
stF.l_whence=SEEK_SET;
stF.l_len=0;

for(i=0;i<1000;i++)
{
        if(fcntl(fd,F_SETLKW,&stF)==-1)
        {
                perror("lock:");
        }

	//lseek(fd,0,SEEK_END);
        if(write(fd,"1",1)!=1)
        {
                perror("write:");
        }
        fstat(fd, &stat);
        printf("%d\n", (int)stat.st_size);

        stF.l_type=F_UNLCK;
        if(fcntl(fd,F_SETLKW,&stF)==-1)
        {
                perror("unlock:");
        }
}

close(fd);
}



二:不是写一次数就解锁一次,而是每个进程写完后,解锁让其他进程继续操作。这种也不会出错。缺点是:其实整体看,其实是多个进程排序执行,实时效果不好。

#include <stdio.h>
#include <fcntl.h>

int main()
{
	struct flock stF;
	int i,n,fd,pid;

	fd=open("./output.txt",O_RDWR|O_CREAT);

	for(i=0;i<99;i++)
	{
		pid=fork();

		if(pid==-1)
		{
		        perror("fork:");
		}
		else if( pid > 0 )
		{
		        break;
		}
	}

	stF.l_type=F_WRLCK;
	stF.l_start=0;
	stF.l_whence=SEEK_SET;
	stF.l_len=0;

	for(i=0;i<1000;i++)
	{
		if(fcntl(fd,F_SETLKW,&stF)==-1)
		{
		        perror("lock:");
		}

		lseek(fd,0,SEEK_END);
		if(write(fd,"1",1)!=1)
		{
		        perror("write:");
		}


	}
	stF.l_type=F_UNLCK;
	if(fcntl(fd,F_SETLKW,&stF)==-1)
	{
		perror("unlock:");
	}
	close(pid);
	close(fd);
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值