1. 程式人生 > >LINUX實現父子進程輪流修改文件的值

LINUX實現父子進程輪流修改文件的值

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實現父子進程輪流修改文件的值