• 4.进程通信


    1.消息队列

      在终端查询消息队列  ipcs -q

      在终端删除消息队列  ipcrm -q 队列ID号 {ipcrm -q key 键值}

     #include <sys/types.h>
     #include <sys/ipc.h>
     #include <sys/msg.h>

      (1)获取键值key  --通过文件路径,加上proj_id组合生成键值key

    key_t ftok(const char *pathname, int proj_id);

        参数:pathname文件路径--文件路径必须存在   /home/gec

                 int proj_id---使用小于128的数据   100

                  一般写成key_t key = ftok(“pathname”,100);

      (2)获取消息队列

    int msgget(key_t key, int msgflg);

        参数:key_t key---键值

               int msgflg ————相当与open函数里面的O_CREAT ---IPC_CREAT|权限

        返回值:返回消息队列的id号,失败返回-1

        一般写成int msgid – msgget(key,IPC_CREAT|0777);

      (3)读写队列

    int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

        参数:int msqid ---队列id类似与文件描述符

                     const void *msgp发送消息内容(数据+标号)

                     size_t msgsz消息数据大小

                     int msgflg 标志一般设置0;

        要发送的内容

    struct msgbuf {
             long mtype;       /* message type, must be > 0 */
                   char mtext[1];    /* message data */
              };

        一般写成msgsnd(msgid,&msgbuffer,sizeof(msgbuffer),0);

    ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);

        参数:int msqid ---队列id类似与文件描述符

                     void *msgp保存读取的消息内容(数据+标号)

                     size_t msgsz 为msgp空间大小

           long msgtyp 数据标志---message type

                      int msgflg 标志一般设置0;

                      一般写成msgrcv(msgid,&msgbuffer,sizeof(msgbuffer),100,0);

        如果队列中没有数据就会阻塞。

      (4)销毁队列

     

    int msgctl(int msqid, int cmd, struct msqid_ds *buf);

     

        参数:int msqid 队列id号

                int cmd 控制命令

                struct msqid_ds *buf--有第二参数决定

                删除队列:把第二个参数cmd设置为IPC_RMID,把第三个参数设置NULL

                   一般写成 int msgdestroy = msgctl(msgid,IPC_RMID,NULL);

    magsend.c
    
    #include <stdio.h>
    #include <sys/types.h>
    #incldude <sys/ipc.h>
    #include <sys/msg.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    int main()
    {
        //获取键值
        key_t key=ftok("/tmp",100);
        printf("key=%d
    ",key);
    
        //通过key获取消息队列
        int msgid=msgget(key,IPC_CREATE|0777);
        if(msgid<0){
            perror("创建消息队列失败
    ");
            return -1;
        }
    
        struct msgbuf{
            long mtype;
            char mtext[128];
        }msgbuffer;
        int i=0;
        while(1){
            msgbuffer.mtype=100;
            sprintf(msgbuffer.mtext,"send data %d",i++);
            //往队列中发送数据
            msgsend(msgid,&msgbuffer,sizeof(msgbuffer),0);
            sleep(1);
        }
    
        //销毁队列
        int msgdestroy=msgctl(key,IPC_RMID,NULL);
        return 0;
    }

    2.共享内存

      ipcs -m查询

      ipcrm -m id号 删除

    头文件

    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>

      (1)获取key值

    int shmget(key_t key, size_t size, int shmflg);

      参数:key_t key--键值

            size_t size--申请共享内存大小 int size = 1920*1080*4;

           int shmflg --权限,创建标准IPC_CREAT

      返回:共享内存id, 失败-1

      一般写成 int shmid = shmget(key,size,IPC_CREAT|0777)

      (2)把内核共享空间映射到用户空间

    void *shmat(int shmid, const void *shmaddr, int shmflg);

      参数:int shmid共享内存id号

             const void *shmaddr,如果为NULL系统自定分配一块用户空间与内核空间映射并且返回首地址,

             int shmflg --权限标准 如果第二个参数设置NULL,此参数可以设置0

      返回值:成功返回映射到用户空间的首地址, 失败(void *) -1

      一般写成 usigned int *mp = shmat(shmid,NULL,0);

      (3)释放映射空间 

    int shmdt(const void *shmaddr);

      一般写成 shmdt(mp);

      (4)释放共享内存

    int shmctl(int shmid, int cmd, struct shmid_ds *buf);

      参数:shmid--共享内存id

            cmd是命令 IPC_RMID

              buf如果是删除这里直接设置NULL

      一般写成  shmctl(shmid, IPC_RMID, NULL);

    shmwrite.c
    
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    int main()
    {
        //获取key值
        key_t key=ftok("/tmp",100);
        //根据key获取共享内存
        int size=1024*640*4;
        int shmid=shmget(key,size,IPC_CREAT|0777);
        //映射空间
        unsigned int *mp=shmat(shmid,NULL,0);
    
        while(1){
            //改变共享内存mp
            unsigned int coloe;
            scanf("%u",&color);
            for(int i=0;i<size/4;i++){
                mp[i]=color;
            }
        }
    
        //释放映射
        shmdt(mp);
        //删除共享内存
        shmctl(shmid,IPC_RMID,NULL);
    }
    shmshow.c
    
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <stdlib.h>
    #include <unistd.h>
    #incllude <sys/mman.h>
    
    int main()
    {
        //获取key
        key_t key=ftok("/tmp",100);
        int size=1024*640*4;
        int shmid=shmget(key,size,IPC_CREAT|0777);
        //映射空间
        unisgned int *mp=shmat(shmid,NULL,0);
    
        //打开lcd
        int fd=open("/dev/fb0",O_RDWR);
        if(fd<0){
            perror("open lcd fail");
        }
        unisgned int *lcdmp=mmap(NULL,size,PORT_READ|PORT_WRITE,MAP_SHARED,fd,0);
    
        for(int i=0;i<size;i++){
            lcdmp[i]=0xff0000;
        }
    
        while(1){
            memcpy(lcdmp,mp,size);
            usleep(1000);
        }
    
        //释放映射
        shmdt(mp);
    
        //删除共享内存
        shmctl(shmid,IPC_RMID,NULL);
    }

    3.信号量

    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/sem.h>

      (1)获取键值key

    key_t ftok(const char *pathname, int proj_id);

      一般用法key_t key = ftok("/tmp", 100);

      (2)通过key值获取信号量

    int semget(key_t key, int nsems, int semflg);

        参数:key_t key键值

                int nsems申请信号量个数

              int semflg 创建标志,权限

        返回值:成功返回信号量id,失败-1

        int semid = semget(key, 2, IPC_CREAT|0777);

       (3)初始化信号量

    int semctl(int semid, int semnum, int cmd, ...);

        参数:int semid信号量id

                int semnum 要设置的信号量编号(编号从0开始)

             第三个参数和第四个采参数相关联

        union semun {
                   int              val;    /* Value for SETVAL */
                   struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
                   unsigned short  *array;  /* Array for GETALL, SETALL */
                   struct seminfo  *__buf;  /* Buffer for IPC_INFO
                                               (Linux-specific) */
               };

          比方说第三个参数是SETVAL,那么第四个参数就是联合体中的val成员

    union semun
        {
            int val;
        } sval;
    
        int val = 1;
        sval.val = 1;
        int ret = semctl(semid, 0, SETVAL, val);

      (4)pv操作,获取和释放资源

    int semop(int semid, struct sembuf *sops, size_t nsops);

        参数:int semid信号量编号

                struct sembuf *sops--pv操作结构体

             size_t nsops--指定第二个参数指针所指向的对象有多少个连续对象

         PV操作之前先要初始化,定义一个结构体

    struct sembuf
    {
    unsigned short  sem_num;  /* semaphore number */
        short   sem_op;   /* semaphore operation */  如果是p操作sem_op 为-1.如果是v操作sem_op值加1
        short   sem_flg;  /* operation flags */
    };

        p操作  sem_p(semid, 0);

        v操作  sem_v(semid, 1);

      (5)释放信号量

    int semctl(int semid, int semnum, int cmd, ...);

        常用  semctl(semid, 0, IPC_RMID, NULL);

    senA.c
    
    void sem_p(int semid, int num)//p操作
    {    
        struct sembuf sbuf;
        sbuf.sem_num = num;
        sbuf.sem_op = -1;
        sbuf.sem_flg = 0;
        semop(semid, &sbuf, 1);
    }
    
    void sem_v(int semid, int num)//v操作
    {    
        struct sembuf sbuf;
        sbuf.sem_num = num;
        sbuf.sem_op = 1;
        sbuf.sem_flg = 0;
        semop(semid, &sbuf, 1);
    }
    
    int main(void)
    {
        //1.获取key
        key_t key = ftok("/tmp", 100);
        //2.获取信号量
        int semid = semget(key, 2, IPC_CREAT|0777);
        //3.初始化信号--编号为0的信号量
        union semun
        {
            int val;
        } sval;
    
        int val = 1;
        sval.val = 1;
        int ret = semctl(semid, 0, SETVAL, val);
    
        while(1)
        {
            //4.p操作
            sem_p(semid, 0);
                
            printf("A进程----操作
    ");
            sleep(1);
        
            //5.v操作
            sem_v(semid, 1);
        }
    
        //释放信号量
        semctl(semid, 0, IPC_RMID, NULL);
    }
    semB.c
    void sem_p(int semid, int num)
    {    
        struct sembuf sbuf;
        sbuf.sem_num = num;
        sbuf.sem_op = -1;
        sbuf.sem_flg = 0;
        semop(semid, &sbuf, 1);
    }
    
    void sem_v(int semid, int num)
    {    
        struct sembuf sbuf;
        sbuf.sem_num = num;
        sbuf.sem_op = 1;
        sbuf.sem_flg = 0;
        semop(semid, &sbuf, 1);
    }
    
    int main(void)
    {
        //1.获取key
        key_t key = ftok("/tmp", 100);
        //2.获取信号量
        int semid = semget(key, 2, IPC_CREAT|0777);
        //3.初始化信号--编号为0的信号量
        #if 0
        union semun
        {
            int val;
        } sval;
    
        int val = 0;
        sval.val = 0;
        int ret = semctl(semid, 1, SETVAL, val);
        #endif 
    
        while(1)
        {
            //4.p操作
            sem_p(semid, 1);
                
            printf("B进程----操作
    ");
            //sleep(1);
        
            //5.v操作
            sem_v(semid, 0);
        }
    
        //释放信号量
    }

    PS:哪里写错了请指正,互相学习。

  • 相关阅读:
    Sharding-JDBC多数据源动态切换
    U 盘安装 CentOS 7 时出现 No Caching mode page found 问题的解决
    sudo 密码直接添加到命令行以方便实现脚本自动化
    Python3 Windows 虚拟环境的若干问题
    20 张图让你彻底弄懂 HTTPS 原理!
    全网写得最好的分库分表之 Sharding-JDBC 中间件介绍
    以为线程池很简单,结果第一道题就被干趴下了!
    以为线程池很简单,没想到第一问就被干趴下了
    分布式事务,看这篇就够了!
    我是一个线程池
  • 原文地址:https://www.cnblogs.com/smallqizhang/p/12455466.html
Copyright © 2020-2023  润新知