我是靠谱客的博主 小巧冬天,最近开发中收集的这篇文章主要介绍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("%dn", (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);
}


最后

以上就是小巧冬天为你收集整理的linux基础之文件锁,读写锁相关的全部内容,希望文章能够帮你解决linux基础之文件锁,读写锁相关所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(41)

评论列表共有 0 条评论

立即
投稿
返回
顶部