写在前面

不得不说,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

  如果对你有帮助点个star吧(●'◡'●)

  总结

  • 不足

    • 没有图形化界面

    • 用信号量和共享内存实现的进程通信只能发送数字消息

    • 创建共享内存空间时,设置权限为了省事设置为0666( 每个进程可读和可写),应该要设置user只能读而不能写,other只能写而不能读

    • 消息队列没有测试msgrcv()函数通过改变msgtype参数来改变接收优先级。

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

    • ...

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

如有不足,欢迎指正!

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

  1. 进程间通信之信号量、消息队列、共享内存(system v的shm和mmap)+信号signal

    进程间通信方式有:System v unix提供3种进程间通信IPC:信号量.消息队列.共享内存.此外,传统方法:信号.管道.socket套接字. [注意上述6种方式只能用户层进程间通信.内核内部有类 ...

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

    Linux下的进程通信手段基本上是从UNIX平台上的进程通信手段继承而来的.而对UNIX发展做出重大贡献的两大主力AT&T的贝尔实验室及BSD(加州大学伯克利分校的伯克利软件发布中心)在进程间 ...

  3. 8.7 进程间的通讯:管道、消息队列、共享内存、信号量、信号、Socket

    进程间的通讯 进程间为什么需要通讯? 共享数据.数据传输.消息通知.进程控制 进程间的通讯有哪些类型? 首先,联系前面讲过的知识,进程之间的用户地址空间是相互独立的,不能进行互相访问,但是,内核空间却 ...

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

    本文概要: 敏捷开发大家想必知道并且评价甚高,缩短开发周期,提高开发质量.将大project独立为不同的小app开发,整个开发过程,程序可用可測,所以提高了总体的质量.基于这样的开发模式和开发理念,进 ...

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

    前言:前面讨论了信号.管道的进程间通信方式,接下来将讨论消息队列. 一.系统V IPC 三种系统V IPC:消息队列.信号量以及共享内存(共享存储器)之间有很多相似之处. 每个内核中的 I P C结构 ...

  6. Linux进程间通信—消息队列

    四.消息队列(Message Queue) 消息队列就是消息的一个链表,它允许一个或者多个进程向它写消息,一个或多个进程向它读消息.Linux维护了一个消息队列向量表:msgque,来表示系统中所有的 ...

  7. Linux进程间通信-消息队列(mqueue)

    前面两篇文章分解介绍了匿名管道和命名管道方式的进程间通信,本文将介绍Linux消息队列(posix)的通信机制和特点. 1.消息队列 消息队列的实现分为两种,一种为System V的消息队列,一种是P ...

  8. Linux 进程间通信 消息队列

    1.特点: 消息队列是IPC对象的一种 消息队列由消息队列ID来唯一标识 消息队列就是一个消息的列表.用户可以在消息队列中添加消息.读取消息等. 消息队列可以按照类型来发送/接收消息(消息的类型是正整 ...

  9. linux进程间通信-消息队列

    一 消息队列的介绍 消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法. 每个数据块都被认为含有一个类型,接收进程可以独立地接收含有不同类型的数据结构. 我们可以通过发送消息来避免命名管道的 ...

随机推荐

  1. Unity在OpenGL模式下Shader编译报错

    报错信息 GLSL compilation failed: 0(21) : error C7528: OpenGL reserves names containing '__' 双击报错VS自动打开V ...

  2. Codeforces Round #524 (Div. 2) C. Masha and two friends(矩形相交)

    C. Masha and two friends time limit per test 1 second memory limit per test 256 megabytes input stan ...

  3. nice和renice命令详解

    基础命令学习目录首页 进程调度是linux中非常重要的概念.linux内核有一套高效复杂的调度机制,能使效率极大化,但有时为了实现特定的要求,需要一定的人工干预.比如,你希望操作系统能分配更多的CPU ...

  4. 读取classpath配置文件的方法

    http://www.cnblogs.com/sprinng/p/5622600.html

  5. MathExam6378

    我的第一个程序 一.预估与实际 PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟) Planning 计划 15 10 • Estima ...

  6. 团队项目--NABCD模型

    蹭课神器 N(need需求) 每个人的兴趣都不一样,或许你很喜欢自己的专业,并且想再进一步学习专业知识:或许你不是太喜欢自己的专业,想上一些自己感兴趣的课程:但是,当你想上你所钟 意的课时,却发现自己 ...

  7. spring 原理

    1.spring原理 内部最核心的就是IOC了,动态注入,让一个对象的创建不用new了,可以自动的生产,这其实就是利用java里的反射,反射其实就是在运行时动态的去创建.调用对象,Spring就是在运 ...

  8. 作业3//Calculator::1

    计算器 作业博客 github 1.扯淡 代码其实是在十几号时打的,花了半晚上加半个下午.但是懒得打随笔,所以到现在才完成. 我的课程里没找到queue,是百度照着瞎打的. 2.总结 不大理解要求,S ...

  9. 【Coursera】线性回归和逻辑回归

    一.线性回归 1.批量梯度下降法 每次对参数进行一次迭代时,都要扫描一遍输入全集 算法可以收敛到局部最优值 当迭代多次之后,每次迭代参数的改变越小 2.随机梯度下降法 对于一个输入样本,对参数进行一次 ...

  10. Beta冲刺(5/7)

    队名:天机组 组员1友林 228(组长) 今日完成:修改代码 明天计划:封装代码 剩余任务:优化网络通讯机制 主要困难:暂无 收获及疑问:暂无 组员2方宜 225 今日完成:优化了ui界面 明天计划: ...