Linux进程间通信(消息队列/信号量+共享内存)

写在前面

不得不说,Deadline果真是第一生产力。不过做出来的东西真的是不堪入目,于是又花了一早上重写代码。


实验内容

进程通信的邮箱方式由操作系统提供形如 send()和 receive()的系统调用来支持,本实验要求学生首先查找资料了解所选用操作系统平台上用于进程通信的系统调用具体形式,然后使用该系统调用编写程序进行进程间的通信,要求程序运行结果可以直观地体现在界面上。在此基础上查找所选用操作系统平台上支持信号量机制的系统调用具体形式,运用生产者与消费者模型设计实现一个简单的信箱,该信箱需要有创建、发信、收信、撤销等函数,至少能够支持两个进程互相交换信息,比较自己实现的信箱与操作系统本身提供的信箱,分析两者之间存在的异同。

背景知识

??消息队列

  • 什么是消息队列

    消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。 每个数据块都被认为含有一个类型,接收进程可以独立地接收含有不同类型的数据结构。我们可以通过发送消息来避免命名管道的同步和阻塞问题。但是消息队列与命名管道一样,每个数据块都有一个最大长度的限制。

    Linux用宏MSGMAX和MSGMNB来限制一条消息的最大长度和一个队列的最大长度。

  • Linux中如何使用消息队列

    Linux提供了一系列消息队列的函数接口来让我们方便地使用它来实现进程间的通信。它的用法与其他两个System V PIC机制,即信号量和共享内存相似。

    • msgget()函数

      该函数用来创建和访问一个消息队列。它的原型为:

      int msgget(key_t key, int msgflg);

      它返回一个以key命名的消息队列的标识符(非零整数),失败时返回-1.

    • msgsnd()函数

      该函数用来把消息添加到消息队列中。它的原型为:

      int msgsend(int msgid, const void *msg_ptr, size_t msg_sz, int msgflg);

      如果调用成功,消息数据的一份副本将被放到消息队列中,并返回0,失败时返回-1.

    • msgrcv()函数

      该函数用来从一个消息队列获取消息,它的原型为:

      int msgrcv(int msgid, void *msg_ptr, size_t msg_st, long int msgtype, int msgflg);

      调用成功时,该函数返回放到接收缓存区中的字节数,消息被复制到由msg_ptr指向的用户分配的缓存区中,然后删除消息队列中的对应消息。失败时返回-1。

    • msgctl()函数

      该函数用来控制消息队列,它与共享内存的shmctl函数相似,它的原型为:

      int msgctl(int msgid, int command, struct msgid_ds *buf);

      成功时返回0,失败时返回-1.

??信号量

  • 什么是信号量

    为了防止出现因多个程序同时访问一个共享资源而引发的一系列问题,我们需要一种方法,它可以通过生成并使用令牌来授权,在任一时刻只能有一个执行线程访问代码的临界区域。临界区域是指执行数据更新的代码需要独占式地执行。而信号量就可以提供这样的一种访问机制,让一个临界区同一时间只有一个线程在访问它,也就是说信号量是用来调协进程对共享资源的访问的。

  • Linux的信号量机制

    Linux提供了一组精心设计的信号量接口来对信号量进行操作,它们不只是针对二进制信号量,下面将会对这些函数进行介绍,但请注意,这些函数都是用来对成组的信号量值进行操作的。它们声明在头文件sys/sem.h中。

    • semget()函数

      它的作用是创建一个新信号量或取得一个已有信号量,原型为:

      int semget(key_t key, int num_sems, int sem_flags);

      成功返回一个相应信号标识符(非零),失败返回-1.

    • semop()函数

      它的作用是改变信号量的值,原型为:

      int semop(int sem_id, struct sembuf *sem_opa, size_t num_sem_ops);

    • semctl()函数

      该函数用来直接控制信号量信息,它的原型为:

      int semctl(int sem_id, int sem_num, int command, ...);

??共享内存

  • 什么是共享内存

    顾名思义,共享内存就是允许两个不相关的进程访问同一个逻辑内存。共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式。不同进程之间共享的内存通常安排为同一段物理内存。进程可以将同一段共享内存连接到它们自己的地址空间中,所有进程都可以访问共享内存中的地址,就好像它们是由用C语言函数malloc()分配的内存一样。而如果某个进程向共享内存写入数据,所做的改动将立即影响到可以访问同一段共享内存的任何其他进程。

    特别提醒:共享内存并未提供同步机制,也就是说,在第一个进程结束对共享内存的写操作之前,并无自动机制可以阻止第二个进程开始对它进行读取。所以我们通常需要用其他的机制来同步对共享内存的访问,例如前面说到的信号量。

  • 共享内存的使用

    与信号量一样,在Linux中也提供了一组函数接口用于使用共享内存,而且使用共享共存的接口还与信号量的非常相似,而且比使用信号量的接口来得简单。它们声明在头文件 sys/shm.h 中。

    • shmget()函数

      该函数用来创建共享内存,它的原型为:

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

      成功时返回一个与key相关的共享内存标识符(非负整数),用于后续的共享内存函数。调用失败返回-1.

    • shmat()函数

      第一次创建完共享内存时,它还不能被任何进程访问,shmat()函数的作用就是用来启动对该共享内存的访问,并把共享内存连接到当前进程的地址空间。它的原型如下:

      void *shmat(int shm_id, const void *shm_addr, int shmflg);

      成功时返回一个指向共享内存第一个字节的指针,如果调用失败返回-1.

    • shmdt()函数

      该函数用于将共享内存从当前进程中分离。注意,将共享内存分离并不是删除它,只是使该共享内存对当前进程不再可用。它的原型如下:

      int shmdt(const void *shmaddr);

      调用成功时返回0,失败时返回-1.

    • shmctl()函数

      与信号量的semctl()函数一样,用来控制共享内存,它的原型如下:

      int shmctl(int shm_id, int command, struct shmid_ds *buf);

参考资料

以上资料全部来源于以下网站:

实验结果

  • 消息队列

  • 信号量+共享内存

完整代码

?Linux-interProcessCommunication

总结

  • 不足

    • 没有图形化界面
    • 用信号量和共享内存实现的进程通信只能发送数字消息
    • 创建共享内存空间时,设置权限为了省事设置为0666( 每个进程可读和可写),应该要设置user只能读而不能写,other只能写而不能读
    • 消息队列没有测试msgrcv()函数通过改变msgtype参数来改变接收优先级。

      > msgtype 可以实现一种简单的接收优先级。如果msgtype为0,就获取队列中的第一个消息。如果它的值大于零,将获取具有相同消息类型的第一个信息。如果它小于零,就获取类型等于或小于msgtype的绝对值的第一个消息。

    —— 引用自Linux进程间通信(七):消息队列 msgget()、msgsend()、msgrcv()、msgctl()

  • 两种方式实现进程间通信的异同
    • 异:消息队列不需要信号量来控制同步和互斥问题,并且可以很方便的改变接收优先级,而共享内存则只能简单的接收按时间排序的消息。
    • 同:一个进程接收到的消息都和另一个进程发送的相同。
  • 心得
    • 由于Linux提供的信号量接口函数都是针对一组信号量进行操作的,因此参数中大部分都需要指定对一组中的哪一个信号量进行操作
    • 共享内存只存放消息缓存区,至于信箱头的那些值仍然存放在各自进程中。


如有不足,欢迎指正!

原文地址:https://www.cnblogs.com/multhree/p/9124839.html

时间: 2024-12-22 00:23:12

Linux进程间通信(消息队列/信号量+共享内存)的相关文章

信号量,消息队列,共享内存中ket_t键值的生成函数ftok。

在System V中,我们经常用用key_t的值来创建或者打开信号量,共享内存和消息队列.这个在IPC的环境中十分的重要,比如说,服务器创建了一个消息队列,等待 客户机发送请求.那么如何创建或者打开已有的消息队列呢?一般而言,我们对于服务器使用的路径和项目id(proj_id)是已知的,所以客户机可以获取 相同的key来打开 消息队列并进行操作.下面就是ftok的使用原型: ftok函数   函数ftok把一个已存在的路径名和一个整数标识得转换成一个key_t值,称为IPC键: # includ

boost进程间通信经常使用开发一篇全(消息队列,共享内存,信号)

本文概要: 敏捷开发大家想必知道并且评价甚高,缩短开发周期,提高开发质量.将大project独立为不同的小app开发,整个开发过程,程序可用可測,所以提高了总体的质量.基于这样的开发模式和开发理念,进程间通信必定是童鞋们必掌握技能之中的一个了,而boost库是众多库中平台支持性非常好,效果非常高之中的一个.做嵌入式或者server等应用的人肯定有所涉及.本文以手冊方式讲述boost共享内存,信号,以及消息队列的编程方式.非常easy,列出最经常使用使用方法,供大家拷贝直接使用.本文出自CSDN-

嵌入式 Linux进程间通信(八)——共享内存

嵌入式 Linux进程间通信(八)--共享内存 一.共享内存 共享内存允许两个或更多进程共享给定的内存区,数据不需要在不同进程间进行复制,是最快的进程间通信方式.使用共享内存唯一需要注意的是多个进程之间对给定存储区的同步访问,但共享内存本身没有提供同步机制,通常使用信号量来实现对共享内存访问的同步. 共享内存编程流程:创建共享内存.映射共享内存.使用共享内存.撤销映射操作.删除共享内存 1.创建共享内存 #include <sys/ipc.h> #include <sys/shm.h&g

linux进程间通信之System V共享内存详解及代码示例

共享内存是最快最为高效的进程间通信方式,当共享内存映射到共享它的某个进程的地址空间后,进程间的数据传递就不再牵扯到内核,进程可以直接读取内核,不需要通过内核系统调用进行数据拷贝.一般使用情况,从共享内存中写入或读取数据的进程间需要做同步,例如通过信号量,互斥锁去同步. 共享内存有System V 共享内存和Posix共享内存,本文介绍System V 共享内存.System V共享内存头文件及相关函数原型:#include <sys/shm.h> int shmget(key_t key, s

Linux进程间通信:管道,信号量,消息队列,信号,共享内存,套接字

Linux下的进程通信手段基本上是从UNIX平台上的进程通信手段继承而来的.而对UNIX发展做出重大贡献的两大主力AT&T的贝尔实验室及BSD(加州大学伯克利分校的伯克利软件发布中心)在进程间的通信方面的侧重点有所不同.前者是对UNIX早期的进程间通信手段进行了系统的改进和扩充,形成了“system V IPC”,其通信进程主要局限在单个计算机内:后者则跳过了该限制,形成了基于套接口(socket)的进程间通信机制.而Linux则把两者的优势都继承了下来 linux进程间通信(IPC)有几种方式

进程间通信第二课--信号量 共享内存 消息队列

信号量 程序中存在一部分临界代码,要确保只有一个进程(或一个执行线程)可以进入临界区代码,并拥有对资源的独占式访问权 我们需要一种方法,通过生成并使用令牌来授权,在任一时刻只能有一个执行线程访问代码的临界区域 这里讲的信号量比在线程的调用中使用的互斥量和信号量更加通用 P:等待,好像位于进入临界区域之前的检查点 V:给予或者释放,好像放弃对临界区域的控制权 P(sv):要是sv的值大于零,就减去1,如果它的值等于零,就挂起该进程的执行 V(sv):要是其他进程因等待sv而被挂起,就让它恢复运行,

Linux进程间通信 -- 消息队列 msgget()、msgsend()、msgrcv()、msgctl()

下面来说说如何用不用消息队列来进行进程间的通信,消息队列与命名管道有很多相似之处.有关命名管道的更多内容可以参阅我的另一篇文章:Linux进程间通信 -- 使用命名管道 一.什么是消息队列 消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法.  每个数据块都被认为含有一个类型,接收进程可以独立地接收含有不同类型的数据结构.我们可以通过发送消息来避免命名管道的同步和阻塞问题.但是消息队列与命名管道一样,每个数据块都有一个最大长度的限制. Linux用宏MSGMAX和MSGMNB来限制一条

详解linux进程间通信-消息队列

前言:前面讨论了信号.管道的进程间通信方式,接下来将讨论消息队列. 一.系统V IPC 三种系统V IPC:消息队列.信号量以及共享内存(共享存储器)之间有很多相似之处. 每个内核中的 I P C结构(消息队列.信号量或共享存储段)都用一个非负整数的标识符( i d e n t i f i e r )加以引用. 无论何时创建I P C结构(调用m s g g e t. s e m g e t或s h m g e t) ,都应指定一个关键字(k e y),关键字的数据类型由系统规定为 k e y

管道,消息队列,共享内存!

2015.1.26星期一,阴天 linux中使用的较多的进程通信方式主要有一下几种:1.管道(Pipe):管道可用于具有亲缘关系进程间的通信,有名管道,除了具有管道所具有功能外,它 还允许无亲缘关系进程的通信2.信号(signal):信号是在软件层次上对中断机制的一种模拟,它是比较复杂的通信方式,用于通知进程 有某事发生,一个进程收到一个信号与处理器收到一个中断请求效果上可以说是一样的3.消息队列:(Messge Queue):消息队列是消息的连接表,包括Posix消息队列SystemV消息队列