zoukankan      html  css  js  c++  java
  • linux 两个进程通过 共享内存 通信例子

    例子1:两个进程通过共享内存通信,一个进程向共享内存中写入数据,另一个进程从共享内存中读出数据

        文件1 创建进程1,实现功能,打印共享内存中的数据

    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <errno.h>
    #include <string.h>
    
    int main(int argc, const char *argv[])
    {
        key_t key;
        int shmid;
        char *p = NULL;
    
        //    key_t ftok(const char *pathname, int proj_id);;
        key = ftok("./app",'b'); //获取唯一的 key 值,
        if(key < 0)
        {
            perror("fail ftok ");
            exit(1);
        }
    
        shmid = shmget(key, 128, IPC_CREAT|IPC_EXCL|0777);//创建/打开共享内存,返回id根据id映射
        if(shmid < 0)
        {
            if(errno == EEXIST)//文件存在时,直接打开文件获取shmid
            {
                printf("file eexist");
                shmid = shmget(key,128,0777);
            }
            else
            {
                perror("shmget fail ");
                exit(1);
            }
        }
        p = (char *)shmat(shmid,NULL,0);//映射,返回地址,根据地址操作
        if( p == (char *)(-1) )
        {
            perror("shmat fail ");
            exit(1);
        }
    
        while(1)
        {
            sleep(1);
            printf("P:%s",p);
            if(strstr(p,"quit") != NULL) //接收到 quit 结束循环
            {
                break;
            }
        }
        shmdt(p);//解除映射
    
        //函数原型 int shmctl(int shmid, int cmd, struct shmid_ds *buf);
        shmctl(shmid,IPC_RMID,NULL); //删除
        return 0;
    }

      文件2  创建进程2 实现功能,获取终端输入的数据写到共享内存中,这两个进程需要同时启动才可以实现通信

    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <errno.h>
    #include <string.h>
    
    int main(int argc, const char *argv[])
    {
        key_t key;
        int shmid;
        char *p = NULL;
        //    key_t ftok(const char *pathname, int proj_id);;
        key = ftok("./app",'b'); //创建key值,
        if(key < 0)
        {
            perror("fail ftok ");
            exit(1);
        }
        shmid = shmget(key,128,IPC_CREAT|IPC_EXCL|0777);//创建/打开共享内存,返回id根据id映射
        if(shmid < 0)
        {
            if(errno == EEXIST)//文件存在时,直接打开文件获取shmid
            {
                printf("file eexist");
                shmid = shmget(key,128,0777); //共享内存存在时,直接打开
            }
            else
            {
                perror("shmget fail ");
                exit(1);
            }
        }
        p = (char *)shmat(shmid,NULL,0);//映射,返回地址,根据地址操作
        if( p == (char *)(-1) )
        {
            perror("shmat fail ");
            exit(1);
        }
        while(1) //接收到 quit 结束循环
        {
            //read 时p中 内容不会清空
            //read(0,p,10);//终端读数据,写入p指向的空间,读取数据时不会清空
            fgets(p,10,stdin);
            if(strstr(p,"quit") != NULL)
            {
                break;
            }
        }
        shmdt(p);//解除映射
    
        //函数原型 int shmctl(int shmid, int cmd, struct shmid_ds *buf);
        shmctl(shmid,IPC_RMID,NULL); //删除
        return 0;
    }

    测试:在进程2终端下输入数据,会在进程1 的终端下打印出来,但是一直打印(输入quit退出循环)

     

    例子2 :使用信号灯集访问临界资源(共享内存)处理上面的一直循环打印的问题

    通过创建包含 2 个信号灯的灯集, 分别控制两个进程访问共享内存  ( 2值信号灯 )

    文件 1  进程1 通过终端输入数据写入共享内存, 两个信号灯,先允许通过终端 输入数据进程操作

    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <errno.h>
    #include <string.h>
    #include <sys/sem.h>
    
    int semid; //信号灯集id
    union semnum
    {
        int val; //信号灯值
    };
    
    union semnum mynum;
    
    struct sembuf mybuf; //定义操作信号灯的结构,PV操作,哪个灯
    
    //参数 信号灯集id 和 是哪个信号灯
    void sem_p(int semid, unsigned short num) //P操作函数
    {
        mybuf.sem_num = num; //第一个信号灯,(信号灯编号)
        mybuf.sem_op = -1; //进行P操作, 为 1 时表示V操作
        mybuf.sem_flg = 0; //阻塞,表示semop函数的操作是阻塞的,直到成功为止
        semop(semid, &mybuf, 1); //最后一个参数,表示操作信号灯的个数
    }
    
    //参数 信号灯集id 和 是哪个信号灯
    void sem_v(int semid, unsigned short num) //V操作函数
    {
        mybuf.sem_num = num;
        mybuf.sem_op = 1;  //1 表示V 操作
        mybuf.sem_flg = 0; //阻塞,表示semop函数的操作是阻塞的,直到操作成功为止
        semop(semid, &mybuf, 1);  //操作的 mybuf 全部变量信号灯集
    }
    
    int main(int argc, const char *argv[])
    {
        key_t key;
        int shmid;
        char *p = NULL;
    
        //    key_t ftok(const char *pathname, int proj_id);;
        key = ftok("./app",'b'); //创建key值,
        if(key < 0)
        {
            perror("fail ftok ");
            exit(1);
        }
    
        //IPC_EXCL | IPC_CREAT 信号灯不存在就创建
        semid = semget(key, 2, IPC_CREAT|IPC_EXCL|0666); //创建信号灯,IPC_EXCL 问信号灯存不存在
        if(semid < 0)
        {
            if(errno == EEXIST)//存在时,只需要打开即可
            {
                semid = semget(key,2,0666); //打开信号灯
            }
            else
            {
                perror("semget fail ");
           exit(1); } }
    else { mynum.val = 0; //设置信号灯值 semctl(semid,0,SETVAL,mynum); //初始化一个信号灯 mynum.val = 1; semctl(semid,1,SETVAL,mynum); } shmid = shmget(key,128,IPC_CREAT|IPC_EXCL|0777);//创建/打开共享内存,返回id根据id映射 if(shmid < 0) { if(errno == EEXIST)//文件存在时,直接打开文件获取shmid { printf("file eexist"); shmid = shmget(key,128,0777); // 直接打开共享内存 } else { perror("shmget fail "); exit(1); } } p = (char *)shmat(shmid,NULL,0);//映射,返回地址,根据地址操作 if( p == (char *)(-1) ) //判断共享内存是否正确 { perror("shmat fail "); exit(1); } while(1) { sem_p(semid, 1); // P 操作 //read 时 p 指向的共享内存中内容不会清空 //read(0,p,10);//终端读数据,写入p指向的空间,读取数据时不会清空 fgets(p,10,stdin); sem_v(semid, 0); // V 操作 if(strstr(p,"quit") != NULL) //当输入 "quit" 退出循环 { break; } } shmdt(p);//解除映射 //int shmctl(int shmid, int cmd, struct shmid_ds *buf); shmctl(shmid,IPC_RMID,NULL); //删除共享内存 semctl(semid,0,IPC_RMID);//删除信号灯 return 0; }

    文件 2  进程2 读取共享内存中的数据, 通过信号灯控制, 当写操作完成时读取一次, 然后等待下次写入

    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <errno.h>
    #include <string.h>
    #include <sys/sem.h>
    
    int semid; //信号灯集id
    union semnum
    {
        int val; //信号灯值
    };
    
    union semnum mynum;
    
    struct sembuf mybuf; //定义操作信号灯的结构
    
    //参数 信号灯集id 和 是哪个信号灯
    void sem_p(int semid, unsigned short num) //P操作函数
    {
        mybuf.sem_num = num; //第一个信号灯,(信号灯编号)
        mybuf.sem_op = -1; //进行P操作, 为 1 时表示V操作
        mybuf.sem_flg = 0; //阻塞,表示semop函数操作是阻塞的,直到成功为止
      //函数semop是对信号灯进行PV操作的函数,通过上面的结构体,参数,确定是P操作还是V操作,确定是对哪个信号灯的PV 操作,simid表示操作的是那个信号灯集 semop(semid, &mybuf, 1); //最后一个参数,表示操作信号灯的个数 } //参数 信号灯集id 和 是哪个信号灯 void sem_v(int semid, unsigned short num) //V操作函数 { mybuf.sem_num = num; mybuf.sem_op = 1; //1 表示V 操作 mybuf.sem_flg = 0; //阻塞,表示semop函数操作是阻塞的,直到成功为止 semop(semid, &mybuf, 1); //操作的 mybuf 全部变量信号灯集 } int main(int argc, const char *argv[]) { key_t key; int shmid; char *p = NULL; // key_t ftok(const char *pathname, int proj_id);; key = ftok("./app",'b'); //创建key值, if(key < 0) { perror("fail ftok "); exit(1); } //IPC_EXCL | IPC_CREAT 信号灯不存在就创建 semid = semget(key, 2, IPC_CREAT|IPC_EXCL|0666); //创建信号灯,IPC_EXCL 问信号灯存不存在 if(semid < 0) { if(errno == EEXIST)//存在时,只需要打开即可 { semid = semget(key,2,0666); //打开信号灯 } else { perror("semget fail "); } } else { mynum.val = 0; //设置信号灯值 semctl(semid,0,SETVAL,mynum); //初始化一个信号灯 mynum.val = 1; semctl(semid,1,SETVAL,mynum); } shmid = shmget(key,128,IPC_CREAT|IPC_EXCL|0777);//创建/打开共享内存,返回id根据id映射 if(shmid < 0) { if(errno == EEXIST)//文件存在时,直接打开文件获取shmid { printf("file eexist"); shmid = shmget(key,128,0777); } else { perror("shmget fail "); exit(1); } } p = (char *)shmat(shmid,NULL,0);//映射,返回地址,根据地址操作 if( p == (char *)(-1) ) { perror("shmat fail "); exit(1); } while(1) { sleep(1); sem_p(semid, 0); printf("P:%s",p); sem_v(semid, 1); // write(0,p,10);//向终端写数据,把p指向的空间的内容 if(strstr(p,"quit") != NULL) { break; } } shmdt(p);//解除映射 //int shmctl(int shmid, int cmd, struct shmid_ds *buf); shmctl(shmid,IPC_RMID,NULL); //删除 semctl(semid,0,IPC_RMID);//删除信号灯 return 0; }

    测试:

    例子2中通过两个2值信号灯实现同步操作,先把写数据到共享内存的信号灯初始化值为1,读共享内存的信号灯初始化为0,让写操作的进程先操作共享内存

  • 相关阅读:
    【LeetCode】306. Additive Number
    【LeetCode】49. Group Anagrams
    【LeetCode】233. Number of Digit One
    【LeetCode】73. Set Matrix Zeroes
    【LeetCode】284. Peeking Iterator
    【LeetCode】241. Different Ways to Add Parentheses
    【LeetCode】289. Game of Life
    新版Java为什么要修改substring的实现
    计算机中整数加法满足结合律吗
    双色球中奖概率分析
  • 原文地址:https://www.cnblogs.com/electronic/p/10946203.html
Copyright © 2011-2022 走看看