LINUX实现父子进程轮流修改文件的值
Posted 项海龙
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LINUX实现父子进程轮流修改文件的值相关的知识,希望对你有一定的参考价值。
本例子是基于信号的同步机制实现父子进程轮流修改文件中的值。
tatic volatile sig_atomic_t sigflag; static sigset_t newmask,oldmask,zeromask; static void sig_usr(int signo) { sigflag=1; } void TELL_WAIT(void) { if(signal(SIGUSR1,sig_usr)==SIG_ERR) perror("signal error"); if(signal(SIGUSR2,sig_usr)==SIG_ERR) perror("signal error"); sigemptyset(&zeromask); sigemptyset(&newmask); sigaddset(&newmask,SIGUSR1); sigaddset(&newmask,SIGUSR2); if(sigprocmask(SIG_BLOCK,&newmask,&oldmask)<0) perror("SIG_BLOCK error"); } void TELL_PARENT(pid_t pid) { kill(pid,SIGUSR2); } void WAIT_PARENT(void) { while(sigflag==0) sigsuspend(&zeromask); sigflag=0; if(sigprocmask(SIG_SETMASK,&oldmask,NULL)) perror("SIG_SETMASK error"); } void TELL_CHILD(pid_t pid) { kill(pid,SIGUSR1); } void WAIT_CHILD(void) { while(sigflag==0) sigsuspend(&zeromask); sigflag=0; if(sigprocmask(SIG_SETMASK,&oldmask,NULL)) perror("SIG_SETMASK error"); }
以上是父子进程通过信号同步的代码实现
开始我是这样写的,先上代码
int main() { int fd; pid_t pid; char buf[3]; int number=0; int len; buf[0]=‘0‘; buf[1]=‘\0‘; if((fd=open("file.txt",O_RDWR|O_CREAT|O_TRUNC|O_SYNC))<0) perror("open file error"); if(write(fd,buf,2)<0) perror("write error"); TELL_WAIT(); if((pid=fork())<0) { perror("fork error"); }else if(pid == 0) { for(;;) { WAIT_PARENT(); lseek(fd,SEEK_SET,0); if((len=read(fd,buf,10))<0) perror("read error"); number=atoi(buf); printf("child number %d\n",number); number++; memset(buf,0,sizeof(buf)); sprintf(buf,"%d",number); buf[strlen(buf)]=‘\0‘; if(open("file.txt",O_RDWR|O_CREAT|O_TRUNC|O_SYNC)<0) perror("open errpr"); // lseek(fd,SEEK_SET,0); if(write(fd,buf,2)<0) perror("write error"); sleep(2); TELL_PARENT(getppid()); } }else { for(;;) { lseek(fd,SEEK_SET,0); if((len=read(fd,buf,10))<0) perror("read error"); number=atoi(buf); printf("parent number : %d\n",number); number++; memset(buf,0,sizeof(buf)); sprintf(buf,"%d",number); if(open("file.txt",O_WRONLY|O_CREAT|O_TRUNC)<0) // perror("open errpr"); // lseek(fd,SEEK_SET,0); if(write(fd,buf,2)<0) perror("write error"); sleep(2); TELL_CHILD(pid); WAIT_CHILD(); } } exit(0); }
首先创建一个文件,往文件中写入0字符。之后父进程中先读取文件中的字符,将文件清空,字符转化为整形后加一后写入文件。子进程和父进程做相同操作。但是运行结果是这样的
parent number : 0 child number 0 parent number : 1 child number 1 parent number : 2 child number 2 parent number : 3
子进程读出的数据并不是父进程写入的数据,似乎父子进程对文件的操作是独立的一样,这不符合父子进程共享同一个文件表项的规则。我反复看了好久,
于是我在父进程清空文件前加了延迟,查看了文件内容,发现正常写入。在清空后进行写入操作后查看文件发现文件内容为空。
sleep(4);
if(open("file.txt",O_WRONLY|O_CREAT|O_TRUNC)<0)
于是调试了一下查看了一下清空前buf的值,发现没有问题
68 sprintf(buf,"%d",number); (gdb) s 69 sleep(3); (gdb) p buf $2 = "1\000" (gdb)
之后运行到第二个睡眠函数时,再查看文件内容,发现文件为空。
那么我猜测问题出在我通过open函数来将文件清空。(这里我也不知道为什么会这样,希望有人能指导一下)
那么我换了一种方法,通过每次写数据直接覆盖原来的数据,而不是将文件长度截断为0,来实现
else if(pid == 0) { for(;;) { WAIT_PARENT(); lseek(fd,SEEK_SET,0); if((len=read(fd,buf,10))<0) perror("read error"); number=atoi(buf); printf("child number %d\n",number); number++; memset(buf,0,sizeof(buf)); sprintf(buf,"%d",number); buf[strlen(buf)]=‘\0‘; // if(open("file.txt",O_RDWR|O_CREAT|O_TRUNC|O_SYNC)<0) // perror("open errpr"); lseek(fd,SEEK_SET,0); if(write(fd,buf,2)<0) perror("write error"); sleep(2); TELL_PARENT(getppid()); } }else { for(;;) { lseek(fd,SEEK_SET,0); if((len=read(fd,buf,10))<0) perror("read error"); number=atoi(buf); printf("parent number : %d\n",number); number++; memset(buf,0,sizeof(buf)); sprintf(buf,"%d",number); // if(open("file.txt",O_WRONLY|O_CREAT|O_TRUNC)<0) // perror("open errpr"); lseek(fd,SEEK_SET,0); if(write(fd,buf,2)<0) perror("write error"); sleep(2); TELL_CHILD(pid); WAIT_CHILD(); } }
parent number : 0 child number 1 parent number : 2 child number 3 parent number : 4 child number 5
以上是关于LINUX实现父子进程轮流修改文件的值的主要内容,如果未能解决你的问题,请参考以下文章