【Linux】进程间通信——system V(共享内存 | 消息队列 | 信号量)(下)

简介: 【Linux】进程间通信——system V(共享内存 | 消息队列 | 信号量)(下)

【Linux】进程间通信——system V(共享内存 | 消息队列 | 信号量)(上)       https://developer.aliyun.com/article/1565752



💫 共享内存的特点

概念:


共享内存的生命周期是随OS的,而不是随进程的,这是所有System V进程间通信的共性。


共享内存的优点:


共享内存是所有进程间通信速度是最快的,因为共享内存是被双方所共享,只要写入对方就能立即看到,能大大减少数据的拷贝次数。


总结:


综合考虑管道和共享内存,考虑键盘输入,和显示器输出,对于同一份数据:共享内存有几次数据拷贝,管道有几次数据拷贝。


管道:需要通过键盘输入到自己定义的缓冲区char buffer[],将数据拷贝到buffer中,调用write接口在把buffer里的数据拷贝到管道里,


另一进程也有定义buffer缓冲区,调用read读取把数据从管道里读取到buffer里,在把数据显示到显示器上:


图解:



共享内存的缺点:


不给我们进行同步和互斥的操作,没有对数据做任何保护。客户端和服务端没做保护,如果想做保护要用到信号量,对共享内存进行保护,写完通过读端进行读取。



🌙 消息队列(了解)


💫 消息队列的概念

消息队列是OS提供的内核级队列,消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法,每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值。


💫 消息队列数据结构

结构如下:

 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) */
               pid_t           msg_lrpid;    /* PID of last msgrcv(2) */
           };
 


消息队列数据结构的第一个成员是msg_perm,它和shm_perm是同一个类型的结构体变量,ipc_perm结构体的定义如下:

     struct ipc_perm {
               key_t          __key;       /* Key supplied to msgget(2) */
               uid_t          uid;         /* Effective UID of owner */
               gid_t          gid;         /* Effective GID of owner */
               uid_t          cuid;        /* Effective UID of creator */
               gid_t          cgid;        /* Effective GID of creator */
               unsigned short mode;        /* Permissions */
               unsigned short __seq;       /* Sequence number */
           };
 


💫 消息队列相关函数

msgget:获取消息队列

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
 
int msgget(key_t key, int msgflg);
 
RETURN VALUE
     If successful, the return value will be the message queue identifier (a nonnegative integer), otherwise -1 with errno indicating the error.


参数讲解:

  • key:ftok函数生成一个key值,这个key值作为msgget函数的第一个参数
  • msgflg:与创建共享内存时使用的shmget函数的第三个参数相同。

返回值:msgget函数返回的一个有效的消息队列标识符

msgctl:控制消息队列

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msqid, int cmd, struct msqid_ds *buf);


msgsnd:发数据

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);


  • msqid:表示消息队列的用户级标识符。
  • msgp:表示待发送的数据块。
  • msgsz:表示所发送数据块的大小
  • msgflg:表示发送数据块的方式,一般默认为0即可

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

msgrcv:读取消息队列

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);


  • msqid:表示消息队列的用户级标识符。msgp:表示获取到的数据块,是一个输出型参数。
  • msgsz:表示要获取数据块的大小
  • msgtyp:表示要接收数据块的类型,msgflg:表示发送数据块的方式,一般默认为0即可
  • 成功返回实际获取到mtext数组中的字节数,失败返回-1。


🌙 信号量(了解)


💫 信号量相关概念

概念:

信号量的本质是一个计数器,通常用来表示公共资源中,资源数的多少问题。信号量主要用于同步和互斥的。


公共资源:


能被多个进程同时访问的资源,访问没有保护的公共资源:数据不一致问题。要让不同的进程看到同一份资源是为了通信,通信是为了让进程间实现协同,而进程之间具有独立性,所以为了解决独立性问题要让进程看到同一份资源,但是会导致数据不一致的问题。


被保护起来的公共资源称为临界资源,而进程要使用资源一定是该进程有对应的代码来访问这部分临界资源称为临界区,但是多个进程看到同一份资源是少数情况,大部分申请自己的资源用自己的代码区访问。有临界区自然就有非临界区,不访问公共资源的代码。


如何保护公共资源:互斥&&同步


互斥:由于各进程要求共享资源,而且有些资源需要互斥使用,因此各进程间竞争使用这些资源,进程的这种关系为进程的互斥


原子性:要么不做、要么做完两态的这种情况。比如支付转账


如果用全局的整数来替代信号量?


全局的整数在父子关系的进程上都看不到,要发生写时拷贝,而不同的进程更看不到,所以进程间想看到同一个计数器得让进程看到同一个计数器。


为什么要信号量?


当我们想要某种资源的时候可以通过信号量进行预;,共享资源被使用的方式:作为一个整体使用;划分成为一个一个的资源部分


图解:



💫 信号量数据结构

结构:

  struct semid_ds {
               struct ipc_perm sem_perm;  /* Ownership and permissions */
               time_t          sem_otime; /* Last semop time */
               time_t          sem_ctime; /* Last change time */
               unsigned long   sem_nsems; /* No. of semaphores in set */
           };
 


信号量数据结构的第一个成员也是ipc_perm类型的结构体变量,ipc_perm结构体的定义如下:

 struct ipc_perm {
               key_t          __key; /* Key supplied to semget(2) */
               uid_t          uid;   /* Effective UID of owner */
               gid_t          gid;   /* Effective GID of owner */
               uid_t          cuid;  /* Effective UID of creator */
               gid_t          cgid;  /* Effective GID of creator */
               unsigned short mode;  /* Permissions */
               unsigned short __seq; /* Sequence number */
           };
 


💫 信号量pv操作

概念:

所有的进程在访问公共资源之前,都必须申请sem信号量,而申请sem信号量的前提是所有进程必须先看到同一个信号量,所以信号量本身就是公共资源,同时,信号量必须保证自身操作的安全性,++,–操作是原子


💫 信号量相关函数

semget:申请信号量

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);
 
RETURN VALUE
 If successful, the return value will be the semaphore set identifier (a nonnegative integer), otherwise -1 is returned, with errno indicating the error.


参数讲解:

  • key:使用ftok函数生成一个key值,这个key值作为semget函数的第一个参数。
  • nsems:表示创建信号量的个数。

第三个参数,与创建共享内存时使用的shmget函数的第三个参数相同。

返回值:信号量集创建成功时,semget函数返回的一个有效的信号量集标识符

semctl:信号量的删除

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semctl(int semid, int semnum, int cmd, ...);


semop:信号量操作

#include <sys/types.h>
 #include <sys/ipc.h>
#include <sys/sem.h>
int semop(int semid, struct sembuf *sops, unsigned nsops);


我们可以发现,共享内存、消息队列、信号量接口相似度非常高,获取与删除,都是system V标准的进程间通信。

OS如何管理:先描述,在组织,对相关资源的内核数据结构做管理,对于共享内存、消息队列、信号量的第一个成员都是ipc_perm:

    struct ipc_perm {
               key_t          __key;    /* Key supplied to shmget(2) */
               uid_t          uid;      /* Effective UID of owner */
               gid_t          gid;      /* Effective GID of owner */
               uid_t          cuid;     /* Effective UID of creator */
               gid_t          cgid;     /* Effective GID of creator */
               unsigned short mode;     /* Permissions + SHM_DEST and
                                           SHM_LOCKED flags */
               unsigned short __seq;    /* Sequence number */
           };


虽然内部的属性差别很大,但是维护它们的数据结构的第一个成员确实一样的,都是ipc_perm类型的成员变量,都可以通过key来标识唯一性。这样设计的好处:在操作系统内可以定义一个struct ipc_perm类型的数组,此时每当我们申请一个IPC资源,就在该数组当中开辟一个这样的结构。((struct shmid_ds*)perms[0],强转,此时就可以访问其他剩下的属性)



🌟结束语 

      今天内容就到这里啦,时间过得很快,大家沉下心来好好学习,会有一定的收获的,大家多多坚持,嘻嘻,成功路上注定孤独,因为坚持的人不多。那请大家举起自己的小手给博主一键三连,有你们的支持是我最大的动力💞💞💞,回见。


目录
相关文章
|
1月前
|
消息中间件 存储 供应链
进程间通信方式-----消息队列通信
【10月更文挑战第29天】消息队列通信是一种强大而灵活的进程间通信机制,它通过异步通信、解耦和缓冲等特性,为分布式系统和多进程应用提供了高效的通信方式。在实际应用中,需要根据具体的需求和场景,合理地选择和使用消息队列,以充分发挥其优势,同时注意其可能带来的复杂性和性能开销等问题。
|
3月前
|
消息中间件
共享内存和信号量的配合机制
【9月更文挑战第16天】本文介绍了进程间通过共享内存通信的机制及其同步保护方法。共享内存可让多个进程像访问本地内存一样进行数据交换,但需解决并发读写问题,通常借助信号量实现同步。文章详细描述了共享内存的创建、映射、解除映射等操作,并展示了如何利用信号量保护共享数据,确保其正确访问。此外,还提供了具体代码示例与步骤说明。
|
4月前
|
消息中间件 Linux 开发者
Linux进程间通信秘籍:管道、消息队列、信号量,一文让你彻底解锁!
【8月更文挑战第25天】本文概述了Linux系统中常用的五种进程间通信(IPC)模式:管道、消息队列、信号量、共享内存与套接字。通过示例代码展示了每种模式的应用场景。了解这些IPC机制及其特点有助于开发者根据具体需求选择合适的通信方式,促进多进程间的高效协作。
188 3
|
4月前
|
开发者 API Windows
从怀旧到革新:看WinForms如何在保持向后兼容性的前提下,借助.NET新平台的力量实现自我进化与应用现代化,让经典桌面应用焕发第二春——我们的WinForms应用转型之路深度剖析
【8月更文挑战第31天】在Windows桌面应用开发中,Windows Forms(WinForms)依然是许多开发者的首选。尽管.NET Framework已演进至.NET 5 及更高版本,WinForms 仍作为核心组件保留,支持现有代码库的同时引入新特性。开发者可将项目迁移至.NET Core,享受性能提升和跨平台能力。迁移时需注意API变更,确保应用平稳过渡。通过自定义样式或第三方控件库,还可增强视觉效果。结合.NET新功能,WinForms 应用不仅能延续既有投资,还能焕发新生。 示例代码展示了如何在.NET Core中创建包含按钮和标签的基本窗口,实现简单的用户交互。
78 0
|
4月前
|
消息中间件 存储 网络协议
从零开始掌握进程间通信:管道、信号、消息队列、共享内存大揭秘
在操作系统中,进程间通信(IPC)是至关重要的,它提供了多种机制来实现不同进程间的数据交换和同步。本篇文章将详细介绍几种常见的IPC方式,包括管道、信号、消息队列、共享内存、信号量和套接字,帮助你深入理解并合理应用这些通信方式,提高系统性能与可靠性。
451 0
|
Linux
Linux 更改共享内存tmpfs的大小
通过挂载的方式在原有目录或新建目录改造 如: [root@luozhonghua /]# df -h Filesystem Size Used Avail Use% Mounted on /dev/mapper/vg_luozhonghua-lv_root 21G 4.
1312 0
|
1月前
|
Linux 网络安全 数据安全/隐私保护
Linux 超级强大的十六进制 dump 工具:XXD 命令,我教你应该如何使用!
在 Linux 系统中,xxd 命令是一个强大的十六进制 dump 工具,可以将文件或数据以十六进制和 ASCII 字符形式显示,帮助用户深入了解和分析数据。本文详细介绍了 xxd 命令的基本用法、高级功能及实际应用案例,包括查看文件内容、指定输出格式、写入文件、数据比较、数据提取、数据转换和数据加密解密等。通过掌握这些技巧,用户可以更高效地处理各种数据问题。
95 8
|
1月前
|
监控 Linux
如何检查 Linux 内存使用量是否耗尽?这 5 个命令堪称绝了!
本文介绍了在Linux系统中检查内存使用情况的5个常用命令:`free`、`top`、`vmstat`、`pidstat` 和 `/proc/meminfo` 文件,帮助用户准确监控内存状态,确保系统稳定运行。
260 6
|
1月前
|
Linux
在 Linux 系统中,“cd”命令用于切换当前工作目录
在 Linux 系统中,“cd”命令用于切换当前工作目录。本文详细介绍了“cd”命令的基本用法和常见技巧,包括使用“.”、“..”、“~”、绝对路径和相对路径,以及快速切换到上一次工作目录等。此外,还探讨了高级技巧,如使用通配符、结合其他命令、在脚本中使用,以及实际应用案例,帮助读者提高工作效率。
80 3
|
1月前
|
监控 安全 Linux
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景,包括 ping(测试连通性)、traceroute(跟踪路由路径)、netstat(显示网络连接信息)、nmap(网络扫描)、ifconfig 和 ip(网络接口配置)。掌握这些命令有助于高效诊断和解决网络问题,保障网络稳定运行。
72 2
下一篇
DataWorks