LINUX實現父子進程輪流修改文件的值
阿新 • • 發佈:2017-08-07
ati per 開始 結果 mic 沒有 不知道 延遲 lseek
本例子是基於信號的同步機制實現父子進程輪流修改文件中的值。
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實現父子進程輪流修改文件的值