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

来源:互联网 发布:迅雷校园招聘java笔试 编辑:程序博客网 时间:2024/06/05 03:16

在看建议锁和强制锁时看到的一个帖子。主要问题是,程序运行理想效果是通过创建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);}


原创粉丝点击