• linux io 学习笔记(03)---共享内存,信号灯,消息队列


    system V IPC

    1)消息队列

    2)共享内存

    3)信号灯(信号量集)

    1.消息队列、

      ipcs -q 查看系统中使用消息队列的情况

      ipcrm -q +msqid 删除消息队列

      消息队列工作原理:在内核空间上创建队列,信息发送者将发送信息打包成结点添加到队列中,信息的接受者选择性从队列上读取想要的节点

      1)创建队列,2)向队列中添加信息,3)从队列中移除信息,4)实现队列的控制(获取队列的属性,设置队列的属性,删除不使用的队列)

      1)创建队列:

          函数原型:key_t ftok(const char *pathname,int proj_id);

          功能  :生成key值

          参数  :pathname 路径名(用户给定,路径必须真实存在)

                proj_id 传字符

          返回值:成功  key值  随机数

              失败:-1

          函数原型:intmsgget(key_t key,int msgflg);

          功能:  创建消息队列

          参数:  key 值  0或非0  key值确保消息队列的唯一性

                msgflg   标志位    IPC_CREAT|IPC_EXCL|0664    创建并打开消息队列(如果消息队列不存在,自动创建,如果存在,返回EEXIST)

                            0664     按该权限打开消息队列。

          返回值:成功:  消息队列标识符

              失败   -1

      2)添加消息

        函数原型:int msgsnd(int msqid,const void *msgp,size_t msgsz,int msgflg);

        功能  :将消息添加到队列的末尾

        参数  :msqid  消息队列的标识符

              msgp  发送的消息

                struct msgbuf{

                      long mtype;  消息的类型

                      char mtext[1];  消息的征文

                    };

              msgsz 消息征文的大小

              msgflg  0  消息队列没空间,写操作阻塞

        返回值  : 成功:0;失败:-1;

      3)将消息从队列中移除

         函数原型:ssize_t masrcv(int msqid,void *msgp,size_t msgsz,long msgtype,int msgflg);

         参数  :msqid 消息队列标识符

              msgp  保存接受的消息(定义和写入时保持一致)

              msgsz  消息正文的大小

              msgtype 消息的类型    0  读取消息队列中的第一个消息

                          >0    读取消息队列中类型为msgtype 的第一个消息

                          <0     读取消息队列中不小于msgtype 的绝对值,且类型最小的第一个消息

              msgflg    0  消息队列中无数据,读操作阻塞

          返回值:成功  消息正文的大小

              失败  -1

      4)对消息队列的控制

          函数原型:int msgctl(int msqid,int cmd,struct msqid_ds *buf);

          功能  :实现对消息队列的控制

          参数  :msqid 消息队列的标识符

              :cmd  制定消息队列的操作处理

                  IPC_STAT   从第三个参数读取消息队列的属性信息

                  IPC_SET  设置消息队列的属性

                  IPC_RMID  删除消息队列

              :buf  描述消息队列属性的结构体          

    struct msqid_ds {

    struct ipc_perm msg_perm; /* Ownership and permissions */ 消息队列的权限
    time_t msg_stime; /* Time of last msgsnd(2) */ 消息队列发送消息的时间
    time_t msg_rtime; /* Time of last msgrcv(2) */ 消息队列接受消息的时间
    time_t msg_ctime; /* Time of last change */ 消息队列改变的时间
    unsigned long __msg_cbytes; /* Current number of bytes in
    queue (nonstandard) */ 消息队列当前的字节数
    msgqnum_t msg_qnum; /* Current number of messages
    in queue */ 消息队列当前消息的个数
    msglen_t msg_qbytes; /* Maximum number of bytes
    allowed in queue */ 消息队列最大的字节数
    pid_t msg_lspid; /* PID of last msgsnd(2) */ 发送消息的用户ID
    pid_t msg_lrpid; /* PID of last msgrcv(2) */ 接收消息的用户ID

    };

    返回值:成功 0
    失败 -1

    实现两个终端数据交互(创建子进程)   

    2.共享内存

      工作原理:系统为每一个进程创建4G的虚拟地址空间,共享内存开辟一块实际的物理内存区域(共享内存区域)将该区域映射给每一个进程

      本质  :多进程实际都是在访问同一块物理内存区域

       其通信效率最高,适用场合:实现实时数据传输

       多进程访问同一块物理内存区域,容易产生竟态,共享内存结合同步互斥机制,保证数据的正确性,任何一个时刻只有一个任务在访问共享的内存区域

      1)申请物理内存区域

        函数原型:int shmget(key_t key,size_t size,int shmflg);

        功能  :开辟实际物理内存区域

        参数  :key:  来自ftok

            :size  物理内存的大小

            :shmflg    IPC_CREAT|IPC_EXCK|0664   创建并打开物理内存(内存不存在,开辟;已存在,报错)

        返回值 :成功     共享内存的标识符

             失败  -1

      2)将物理内存映射到进程的虚拟地址空间上(进程只需要操作属于自己的虚拟地址空间,本质访问实际物理内存)

        函数原型: void *shmat(int shmid,const void *shmaddr,int shmflg);

        功能  :将物理内存区域映射到进程的虚拟地址空间(将物理地址转换为虚拟地址)

        参数  :shmid  共享内存标识符

            :shmaddr  NULL   将物理内存映射进程一个合理的位置(未使用,且内存足够大区域)

            :shmflg  0  对于共享内存段,可以实现读写

        返回值  :成功  链接物理内存的虚拟地址

              失败   -1

      3)将物理内存释放

        函数原型:int shmctl(int shmid,int cmd,struct shmid_ds *buf);

        功能  :实现对共享内存的控制

        参数  :shmid  共享内存的标识符

            :cmd  制定对共享内存的操作

                  IPC_STAT   从第三个参数中读取共享内存的属性信息

                  IPC_SET  设置共享内存的属性信息

                  IPC_RMID  删除共享内存

            :buf  描述共享内存属性的结构体

    struct shmid_ds {  
    struct ipc_perm shm_perm; /* Ownership and permissions */ 访问的权限
    size_t shm_segsz; /* Size of segment (bytes) */ 共享内存的大小
    time_t shm_atime; /* Last attach time */ 上一次被映射的时间
    time_t shm_dtime; /* Last detach time */ 上一次被断开映射的时间
    time_t shm_ctime; /* Last change time */ 上一次改变的时间
    pid_t shm_cpid; /* PID of creator */ 创建共享内存的用户ID
    pid_t shm_lpid; /* PID of last shmat(2)/shmdt(2) */ 上一次执行映射和断开映射的进程ID
    shmatt_t shm_nattch; /* No. of current attaches */ 被映射的次数(编号)
    ...
    };
    返回值:成功 0
    失败 -1

     

     4.信号灯

      信号灯:信号量集

      信号量的核心:PV操作

      1)创建多个信号量

        函数原型:int semget(key_t key,int nsems,int semflg);

        功能  :创建或打开多个信号量

        参数  :key 值   ftok

            :nsems   创建或打开信号量的个数

            :semflg   IPC_CREAT|IPC_EXCL|0664    创建并打开信号量(信号量存在,报错,不存在,自动创建)

            : 0664     打开信号量集的标识符

        返回值: 成功:信号量集的标识符,失败:-1

      2)申请,释放信号量

        函数原型:int semop(int semid,struct sembuf *sops,unsigned nsops);

        功能  :实现对信号量集的操作

        参数  :semid 信号量集的标识符

            :  sops:

    struct sembuf{
      unsigned short sem_num; /* semaphore number */ 信号量的编号
      short sem_op; /* semaphore operation */
          1   释放信号量 值+1
          0 等待信号量的值变为0
          -1 申请信号量 值-1
    short sem_flg; /* operation flags */ 默认为0
    }
    nsops 本次函数操作的信号量的个数
    返回值:成功 0
    失败 -1

       3)信号量集的控制

    函数原型:int semctl(int semid, int semnum, int cmd, ...);
    功能:实现对信号量集中某一个信号量的控制
    参数:semid 信号量集的标识符
    semnum 信号量集信号量的编号
    cmd 指定对信号量的控制
    IPC_STAT 获取信号量的属性信息
    IPC_SET 设置信号量的属性信息
    IPC_RMID 删除信号量
    SETVAL 设置第semnum个信号量的初始值
    GETVAL 获取第semnum个信号量的值
    返回值:成功 0
    GETVAL 当前信号量的值

    失败 -1
      ... 附件参数
     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) */
      };
    信号量的属性
    truct semid_ds {
      struct ipc_perm sem_perm; /* Ownership and permissions */ 访问的权限
      time_t sem_otime; /* Last semop time */ 上一次PV操作的时间
      time_t sem_ctime; /* Last change time */ 上一次改变的时间
      unsigned short sem_nsems; /* No. of semaphores in set */ 信号量集合中信号量个数
    };

  • 相关阅读:
    hdu多校4
    hdu多校第三场
    牛客多校4
    bzoj 1477 扩展欧几里德
    bzoj 1485 卡特兰数 + 分解因子
    hdu多校 2
    牛客网暑期多校2
    bzoj 1040 基向内环树dp
    hdu 多校第一场
    SPOJ
  • 原文地址:https://www.cnblogs.com/jiaan/p/9403378.html
Copyright © 2020-2023  润新知