zoukankan      html  css  js  c++  java
  • 【Linux计划】XSI IPC

    三种IPC这就是所谓的XSI IPC,每间:
    • 消息队列
    • 信号量
    • 共享存储器
    以下分别介绍三种IPC的使用方法。

    1、消息队列
    消息队列是消息的链接表,具有例如以下函数接口:
    • msgget:创建一个新队列或打开一个现存的队列。
    • msgsnd:将消息加入到队列尾端。
    • msgrcv:从队列中取消息。
    我们能够自行定义一个表示消息的结构体,它由类型字段和实际数据组成:
    struct mest_t {
        long type;          // 消息类型
        char text[512];     // 消息内容
    };


    有了消息类型。当我们用msgrcv函数取消息时,就不一定要以先进先出的顺序,而是能够依据消息类型取消息了。以下是一段简单的測试代码:
    #include <stdio.h>
    #include <sys/msg.h>
    #include <sys/types.h>
    #include <string.h>
    #include <errno.h>
     
    struct mest_t {
        long type;
        char text[512];
    };
     
    int main(void)
    {
        pid_t pid;
        int mq_id;
        struct mest_t msg;
     
        /* IPC_PRIVATE用于创建一个新队列
         * 设置了IPC_EXCL而且设置了IPC_CREAT。当文件存在时返回错误
         */
        mq_id = msgget(IPC_PRIVATE, IPC_CREAT | IPC_EXCL);
        if (mq_id == EEXIST)
            return -1;  /* 返回EEXIST表示IPC已存在 */
     
        if ((pid = fork()) < 0)
            return -1;
        else if (pid == 0)
        {
            /* 子进程 */
            msg.type = 123;                     /* 消息类型 */
            strcpy(msg.text, "Hello world!");   /* 消息内容 */
     
            /* 非堵塞方式将消息放入消息队列
             * 队列已满则返回EAGAIN
             */
            while (msgsnd(mq_id, (long *)&msg, 512, IPC_NOWAIT) == EAGAIN)
                sleep(1);
        }
        else
        {
            /* 非堵塞方式从队列中取消息
             * 假设没有指定类型的消息。函数返回-1,errno设置为ENOMSG
             */
            while (msgrcv(mq_id, (long *)&msg, 512, 123, IPC_NOWAIT) == -1)
            {
                if (errno == ENOMSG)
                {
                    printf("There is no this type message!
    ");
                    sleep(1);
                }
            }
     
            printf("%s
    ", msg.text);
        }
      
        return 0;
    }


    当父进程须要取的消息类型和子进程发送的消息类型同样时。执行结果例如以下:


    父进程可以非常快接收到子进程发送到消息队列中的消息。

    可是改动msgrcv的消息类型參数后,执行结果例如以下:



    父进程得不到想要的消息,一直打印错误信息。

    2、信号量
    信号量是一个计数器。用于多进程对共享数据对象的訪问。步骤例如以下:
    • 測试控制该资源的信号量。
    • 若此信号量的值为正。则进程能够使用该资源。进程将信号量值减1,表示它使用了一个资源单位。
    • 若此信号量的值为0。则进程进入休眠状态,直至信号量大于0。进程被唤醒后。它返回至第一步。
    当进程不再使用由一个信号量控制的共享资源时,该信号量值增1。假设有进程正在休眠等待此信号量,则唤醒它们。

    3、共享存储
    共享存储同意多个进程共享一块给定的存储区。是最快的一种IPC。測试代码例如以下:
    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/shm.h>
     
    #define SHM_SIZE 100
    #define SHM_MODE (SHM_W | SHM_R |  IPC_CREAT)
     
    int main()
    {
        int shmid;
        char *shmptr;
        pid_t pid;
     
        /* 获得共享存储标识符 */
        if ((shmid = shmget(IPC_PRIVATE, SHM_SIZE, SHM_MODE)) < 0)
            return -1;
     
        if ((pid = fork()) < 0)
            return -1;
        else if (pid == 0)
        {
            shmptr = shmat(shmid, 0, 0);    /* 參数2为0表示由内核分配共享空间 */
            printf("Child attached shared memory is : %lx
    ", (unsigned long)shmptr);
            shmdt(shmptr);                  /* 使进程脱离该共享空间 */
        }
        else
        {
            waitpid(pid, NULL, 0);
     
            shmptr = shmat(shmid, 0, 0);
            printf("Parent attached shared memory is : %lx
    ", (unsigned long)shmptr);
            shmdt(shmptr);
     
            shmctl(shmid, IPC_RMID, 0);  /* 删除该共享存储段 */
        }
     
        return 0;
    }


    执行结果:


    从上面的实验结果能够看出,父、子进程共享了同一个存储段。

    有一点须要注意,shmdt函数仅仅是让进程脱离该共享存储段,但该存储段依旧存在而且shmid依旧有效。它是与shmat相相应的。而还有一个函数shmctl使用IPC_RMID參数时才是真正删除该共享段。


    共享存储段和存储映射I/O中的mmap函数很相似,它们之间的差别是:mmap映射的存储段是与文件相关联的,XSI共享存储段则并无这样的关联。

    参考:
    《unix编程环境》 P415-P432.
  • 相关阅读:
    【sql:练习题3】查询在 SC 表存在成绩的学生信息
    【sql:练习题2】查询平均成绩大于等于 60 分的同学的学生编号和学生姓名和平均成绩
    学习设计模式之动态代理
    学习设计模式之静态代理
    学习设计模式之装饰器模式
    学习设计模式之策略模式
    学习设计模式之简单工厂
    Ehcache3.x学习(二)分层的选项
    Ehcache3.x学习(一)入门
    java进行微信h5支付开发
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/4590238.html
Copyright © 2011-2022 走看看