• 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]='';
        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
    ",number);
                number++;
                memset(buf,0,sizeof(buf));
                sprintf(buf,"%d",number);
                buf[strlen(buf)]='';
                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
    ",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 = "100"
    (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
    ",number);
                number++;
                memset(buf,0,sizeof(buf));
                sprintf(buf,"%d",number);
                buf[strlen(buf)]='';
    //            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
    ",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
  • 相关阅读:
    PE 合并节
    VirtualAddress与VirtualSize与SizeOfRawData与PointerToRawData的关系
    .net core publish 找不到视图
    c++ rc 文件内包含中文字符导致在unicod环境下编译乱码
    .net 5.0 ref文件夹的作用
    .net 5.0项目升级工具
    HttpWebRequest DNS缓存清理
    .net 5.0 发布命令总结
    关于dll not found 排查解决
    关于win7 无法识别sha256签名导致驱动无法安装的问题
  • 原文地址:https://www.cnblogs.com/a-lai/p/7301288.html
Copyright © 2020-2023  润新知