0%

Linux程序设计-进程间通信IPC [总结概况版][复习专用][速通]

导航

当前章节:管道
原文链接:进程间通信IPC
上一章节:线程
下一章节:网络通信socket
目录:Linux程序设计

IPC

介绍

IPC代表进程间通信。它指的是不同进程之间可以相互通信的机制。
Linux中一些常见的IPC方法包括:pipe,share memory,message queue, semaphores,signal,socket
管道,信号量我们上文已经了解了,本节主要了解消息队列、共享内存以及支持不同进程间的信号量机制。socket在下一节单独学习。

message queue

消息队列是Linux中进程间通信的一种方法。它们允许进程以数据块的形式交换消息。
消息队列有mquque和sys/msg、sys/ipc两种实现

mquque

关于消息队列的一些关键点:
1. 使用mq_open()创建。这指定了最大消息大小、消息数量等属性。
2. 使用mq_send()将消息写入队列,并使用mq_receive()从队列中读取消息。
3. 消息按写入顺序(FIFO)从队列中读取。
4. 每条消息都有一个优先级,优先级较高的消息在优先级较低的消息之前读取。
5. 消息将保留在队列中直到被读取。队列将在mq_send()块之前容纳最大数量的消息。
6. 打开队列时,消息具有指定的最大大小。较大的邮件将被拒绝。
7. 消息队列由文件系统中的一个名称标识。
8. 进程必须具有对队列的读取和/或写入访问权限才能使用它。在打开队列时指定访问权限。

ipc msg https://blog.csdn.net/guoping16/article/details/6584024

  1. 创建msg:int msgget(key_t key, int msgflg);
    1.key-用于标识消息队列的密钥。这可以是任意整数,也可以是预定义值之一:
    -IPC_PRIVATE-专用队列,不由密钥标识
    -IPC_RMID-删除带有此密钥的消息队列
    -IPC_CREAT-如果消息队列不存在,则创建该队列
    2.msgflg-队列的权限标志。应为0666,以允许所有用户进行读/写访问。
    IPC_CREAT也可以与此进行“或”运算,以在队列不存在的情况下创建队列。

  2. 接收
    ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long int msgtype, int msgflg);
    msgrcv(qid, buf, sizeof(buf), 0, MSG_NOERROR);
    出错:-1,错误原因存于error中
    成功:实际读取到的消息数据长度
    1.msqid-消息队列标识符
    2.msgp-指向接收消息缓冲区的指针
    3.msgsz-缓冲区的大小(以字节为单位)
    4.消息类型-要接收的消息类型(0接收第一条消息)
    5.msgflg-消息标志(MSG_NOERROR允许接收截断的消息)
    0: 阻塞式接收消息,没有该类型的消息msgrcv函数一直阻塞等待
    IPC_NOWAIT:如果没有返回条件的消息调用立即返回,此时错误码为ENOMSG
    IPC_EXCEPT:与msgtype配合使用返回队列中第一个类型不为msgtype的消息
    IPC_NOERROR:如果队列中满足条件的消息内容大于所请求的size字节,则把该消息截断,截断部分将被丢弃

  3. 发送
    int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
    msgsnd(qid, msg, sizeof(msg), 0);
    成功:0
    出错:-1,错误原因存于error中
    1.msqid-由msgget()返回的消息队列标识符
    2.msgp-指向消息缓冲区的指针
    3.msgsz-消息的大小(以字节为单位)
    4.msgflg-消息标志(通常为0)
    0:当消息队列满时,msgsnd将会阻塞,直到消息能写进消息队列
    IPC_NOWAIT:当消息队列已满的时候,msgsnd函数不等待立即返回
    IPC_NOERROR:若发送的消息大于size字节,则把该消息截断,截断部分将被丢弃,且不通知发送进程。

4.控制
int msgctl(int msqid, int cmd, struct msqid_ds *buf)

  • IPC_STAT-使用队列详细信息填充buf
  • IPC_SET-从buf设置队列详细信息
  • IPC_RMID-删除消息队列

5.提醒

  • qid一般不会为0,如果为0注意qid不会报错且有可能是直接被条件语句赋值了
  • 发和收传入参数大小为消息大小,消息结构首个必须为long类型作为类别,且消息类别要求大于0

差异

但总的来说,它们提供了非常相似的消息队列功能,具有相同的基本使用模式。主要的区别是句法上的。

share memory

共享内存允许多个进程访问同一内存区域。这是流程进行通信和共享数据的一种有用方式。
关于共享内存的一些关键点:

  • 它由一个进程分配,并且可以由多个其他进程访问。
  • 进程连接到共享内存和从共享内存分离,但它会一直存在,直到明确删除为止。
  • 共享内存由一个密钥和创建者过程来标识。其他进程使用该密钥连接到同一共享内存。
  • 可以设置权限来控制哪些用户/进程可以访问。
  • 大小是在创建共享内存时设置的,并且不会更改。进程必须确保它们的写入不会超过分配的大小。
  • 进程可以直接读取和写入共享内存,而无需协调或发送消息。
  • 不能使用标准文件I/O功能(读、写)。提供了特殊的共享内存功能。
  • 比使用文件系统进行IPC更快,因为内核不需要在进程和文件系统之间复制数据。
  1. 创建
    int shmget(key_t key, size_t size, int shmflg);
    int shm_id = shmget(IPC_PRIVATE, 1024, 0666 | IPC_CREAT);
    key为唯一序列,shmflg与open参数类似,指定IPC_CREATE和文件权限,创建失败返回-1,否则返回共享内存文件标识符

  2. 连接
    void *shmat(int shmid, const void shmaddr, int shmflg);
    void
    shm_ptr = shmat(shm_id, NULL, 0);

  • 链接成功返回一个指向内存的指针shm_ptr,失败返回-1
  • 它用于连接到现有的共享内存段,以便您可以访问它。
  • shmid指定从shmget()获得的段的ID。
  • shaddr通常为NULL,表示系统应该选择一个可用的地址。
  • shmflg通常为0。其他标志包括:
    SHM_RDONLY-附加只读

    SHM_REMAP-替换同一内存区域的任何现有映射
  • shmat()返回的指针可以被取消引用,并像普通指针一样用于访问共享内存。
  • 在使用shmctl(IPC_RMID)删除共享内存之前,所有进程都必须从共享内存中分离。
  1. 解除指针连接
    shmdt(shm_ptr);

  2. 移除共享内存
    shmctl(shm_id, IPC_RMID, NULL);