【Linux】进程间通信——system V共享内存、共享内存的概念、共享内存函数、system V消息队列、信号量

文章目录

  • 进程间通信
    • 1.system V共享内存
      • 1.1共享内存原理
      • 1.2共享内存数据结构
      • 1.3共享内存函数
    • 2.system V消息队列
      • 2.1消息队列原理
    • 3.system V信号量
      • 3.1信号量原理
      • 3.2进程互斥
    • 4.共享内存的使用示例

进程间通信

1.system V共享内存

1.1共享内存原理

  共享内存区是最快的IPC形式。一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据。
在这里插入图片描述

本质:还是先让不同的进程看到同一份资源。

  所以,共享内存是Unix下的多进程之间的通信方法,允许多个进程访问同一个内存空间,是在多个进程之间共享和传递数据最高效的方式。共享内存本质上是一块物理内存,多个进程通过将同一块物理内存都映射到自己的虚拟地址空间,通过自己的虚拟地址进行访问,实现数据间的共享。

  如果某个进程修改了共享内存中的数据,其它的进程读到的数据也将会改变。但是需要注意的是,共享内存并未提供锁机制,也就是说,在某一个进程对共享内存的进行读写的时候,不会阻止其它的进程对它的读写。如果要对共享内存的读/写加锁,可以使用信号灯。

  

1.2共享内存数据结构

struct shmid_ds {struct ipc_perm shm_perm; /* operation perms */int shm_segsz; /* size of segment (bytes) */__kernel_time_t shm_atime; /* last attach time */__kernel_time_t shm_dtime; /* last detach time */__kernel_time_t shm_ctime; /* last change time */__kernel_ipc_pid_t shm_cpid; /* pid of creator */__kernel_ipc_pid_t shm_lpid; /* pid of last operator */unsigned short shm_nattch; /* no. of current attaches */unsigned short shm_unused; /* compatibility */void *shm_unused2; /* ditto - used by DIPC */void *shm_unused3; /* unused */
};

  Linux的共享内存数据结构是struct shmid_ds,它定义了共享内存的一些重要属性。这个结构体包括以下字段:

  struct ipc_perm shm_perm:这个字段包含了操作权限,如读、写和执行等。

  int shm_segsz:这个字段表示共享内存段的字节大小。

  __kernel_time_t shm_atime:这个字段表示最后一次附加的时间。

  __kernel_time_t shm_dtime:这个字段表示最后一次分离的时间。

  __kernel_time_t shm_ctime:这个字段表示最后一次更改的时间。

  __kernel_ipc_pid_t shm_cpid:这个字段表示创建者的进程ID。

  __kernel_ipc_pid_t shm_lpid:这个字段表示最后一次操作共享内存的进程ID。

  unsigned short shm_nattch:这个字段表示当前附加到共享内存的进程数。

  unsigned short shm_unused:这个字段是用于兼容的,目前未使用。

  这个结构体主要用于在Linux内核中描述POSIX共享内存(即System V共享内存)。在用户空间中,通常使用的是shmget(), shmat(), shmdat()等系统调用与内核的POSIX共享内存交互。

  

1.3共享内存函数

  shmget函数

在这里插入图片描述
  功能:用来创建共享内存

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

  参数:
   key:这个共享内存段名字
   size:共享内存大小
   shmflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的

  返回值:成功返回一个非负整数,即该共享内存段的标识码;失败返回-1。

  

shmat函数
在这里插入图片描述

  功能:将共享内存段连接到进程地址空间

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

  参数:
   shmid: 共享内存标识
   shmaddr:指定连接的地址
   shmflg:它的两个可能取值是SHM_RND和SHM_RDONLY

  返回值:成功返回一个指针,指向共享内存第一个节;失败返回-1

  注意:
  shmaddr为NULL,核心自动选择一个地址
  shmaddr不为NULL且shmflg无SHM_RND标记,则以shmaddr为连接地址。
  shmaddr不为NULL且shmflg设置了SHM_RND标记,则连接的地址会自动向下调整为SHMLBA的整数倍。公式:shmaddr - (shmaddr % SHMLBA)
shmflg=SHM_RDONLY,表示连接操作用来只读共享内存

  

shmdt函数
在这里插入图片描述
  功能:将共享内存段与当前进程脱离
  原型:int shmdt(const void *shmaddr);

  参数:
  shmaddr: 由shmat所返回的指针

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

  注意:将共享内存段与当前进程脱离不等于删除共享内存段

  
shmctl函数
在这里插入图片描述

  功能:用于控制共享内存
  原型:int shmctl(int shmid, int cmd, struct shmid_ds *buf);

  参数
  shmid:由shmget返回的共享内存标识码
  cmd:将要采取的动作(有三个可取值)
  buf:指向一个保存着共享内存的模式状态和访问权限的数据结构

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

在这里插入图片描述
  

2.system V消息队列

  消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法。

  每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值。

  特性方面:IPC资源必须删除,否则不会自动清除, 除非重启,所以system V IPC资源的生命周期随内核。

  

2.1消息队列原理

在这里插入图片描述

  System V消息队列的原理是基于消息块的数据结构,可以在进程间传递数据。每个消息块都有一个类型和信息两部分构成。两个进程可以通过System V消息队列互相发送和接收消息。发送消息时,进程将数据块添加到消息队列的队尾,接收消息时,进程从消息队列的队头获取数据块。

  需要注意的是,System V消息队列的资源必须自行删除,否则不会自动清除,因为System V IPC资源的生命周期是随内核的。同时,消息队列数据结构也可能会存在大量的消息队列,系统也必须为消息队列维护相关的内核数据结构。
  

3.system V信号量

3.1信号量原理

  System V信号量集(也称为信号量)的原理是基于一种数据操作锁(相当于资源计数器),用于同步和协调多个进程之间的数据交换。它自身不具备数据交换功能。

  信号量的工作原理基于两种原子性操作:wait(p)和signal(v)。 当一个进程进行wait(p)操作时,如果信号量的值大于0,则该进程可以继续执行并使用一个资源,将信号量的值减1;如果信号量的值为0,则该进程会被阻塞,直到其他进程释放资源,使信号量的值大于0为止。当一个进程进行signal(v)操作时,如果信号量的值小于等于0,则该进程可以继续执行并使用一个资源,将信号量的值加1;如果信号量的值大于0,则进程不会得到资源,因为已有其他进程在使用资源。

  信号量的作用是维护资源的互斥和多进程的同步访问,以确保在一个时间点只有一个进程可以访问共享资源,从而避免了多个进程同时访问共享资源而引起的竞争条件。 同时,信号量也可以用于控制多个进程之间的同步和通信。
  

3.2进程互斥

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

  系统中某些资源一次只允许一个进程使用,称这样的资源为临界资源或互斥资源。

  在进程中涉及到互斥资源的程序段叫临界区。

  特性方面:IPC资源必须删除,否则不会自动清除,除非重启,所以system V IPC资源的生命周期随内核。
  

4.共享内存的使用示例

makefile

.PHONY:all
all:server client
client:client.c comm.cgcc -o $@ $^
server:server.c comm.cgcc -o $@ $^.PHONY:clean
clean:rm -f client server

  
comm.h

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>#define PATHNAME "."
#define PROJ_ID 0x6666int createShm(int size);
int destroyShm(int shmid);
int getShm(int size);#endif

  
comm.c

static int commShm(int size, int flags)
{key_t _key = ftok(PATHNAME, PROJ_ID);if(_key < 0){perror("ftok");return -1;}int shmid = 0;if( (shmid = shmget(_key, size, flags)) < 0){perror("shmget");return -2;}return shmid; 
}int destroyShm(int shmid)
{if(shmctl(shmid, IPC_RMID, NULL) < 0){perror("shmctl");return -1;}return 0;
}int createShm(int size)
{return commShm(size, IPC_CREAT|IPC_EXCL|0666);
}int getShm(int size)
{return commShm(size, IPC_CREAT);
}

  
server.c

#include "comm.h"
int main()
{int shmid = createShm(4096);char *addr = shmat(shmid, NULL, 0);sleep(2);int i = 0;while(i++<26){printf("client# %s\n", addr);sleep(1);}shmdt(addr);sleep(2);destroyShm(shmid);return 0;
}

  
client.c

#include "comm.h"
int main()
{int shmid = getShm(4096);sleep(1);char *addr = shmat(shmid, NULL, 0);sleep(2);int i = 0;while(i<26){addr[i] = 'A'+i;i++;addr[i] = 0;sleep(1);}shmdt(addr);sleep(2);return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/219276.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2018年1月22日 Go生态洞察:Hello, 中国!

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

罗技M590鼠标usb优联连接不上

手里有一个罗技M590鼠标从18年4月一直用到现在&#xff0c;质量很好&#xff0c;除了滚轮有些松别的没毛病。最近一台笔记本电脑办公不太够用&#xff0c;又领了一个台式机&#xff0c;就想到M590支持双模连接&#xff0c;并且支持Flow&#xff0c;就把usb优联接收器从电池仓拿…

球面的表面积

此推导需要用到重积分的知识&#xff0c;另外关于曲面的面积公式可以看我之前的博客

[架构之路-251]:目标系统 - 设计方法 - 软件工程 - 软件建模 - 什么是建模,什么是软件系统建模?软件系统阶段性建模?正向建模与反向建模?

目录 前言&#xff1a; 一、什么是建模 1.1 什么是建模 1.2 常见的建模的方式与种类 二、什么是软件系统建模 2.1 软件系统建模的概念 2.2 软件系统常见的三种建模方法和手段 2.3 软件系统建模的常见工具 三、软件系统阶段性建模 3.1 软件工程在不同阶段对软件系统进…

【JavaEE初阶】浅谈进程

✏️✏️✏️今天正式进入JavaEE初阶的学习&#xff0c;给大家分享一下关于进程的一些基础知识。了解这部分内容&#xff0c;只是为后续多线程编程打好基础&#xff0c;因此进程部分的知识&#xff0c;不需要了解更加细节的内容。 清风的CSDN博客 &#x1f61b;&#x1f61b;&a…

蓝桥杯每日一题2023.11.24

题目描述 #include <stdio.h> #define N 100int connected(int* m, int p, int q) {return m[p]m[q]? 1 : 0; }void link(int* m, int p, int q) {int i;if(connected(m,p,q)) return;int pID m[p];int qID m[q];for(i0; i<N; i) ________________________________…

杂货铺 | Windows系统上解压缩tgz文件

文章目录 &#x1f4da;快速终端打开实现 & 解压缩实现步骤&#x1f4da;环境变量的一般配置步骤 & 问题解决思路 &#x1f4da;快速终端打开实现 & 解压缩实现步骤 将对应的tgz文件放入对应的文件夹。快速在指定文件夹下打开终端 打开对应的路径 双击地址栏 然后…

Harmony开发 eTs公共样式抽取

Harmony系统开发使用eTs开发过程中对于样式相同且重复使用的样式可以抽取成公共样式循环利用&#xff0c;类似于android的style样式。 import router from ohos.router import cryptoFramework from ohos.security.cryptoFramework; import prompt from system.prompt class L…

2018年2月16日 Go生态洞察:Go 1.10版本发布分析

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

【教学类-06-12】20231126 (一)如何让加减乘除题目从小到大排序(以1-20之间加法为例,做正序排列用)

结果展示 优化后 优化前 背景需求&#xff1a; 生成列表 单独抽取显示题目排序方法 存在问题: 我希望 00 01 02……这样排序&#xff0c;但是实际上&#xff0c;除了第一个加数会从小到大排序&#xff0c;第二个被加数的第十位数和个位数都会从小到大排序&#xff0c;也就是…

express中间件

1.中间件的格式 Express的中间件&#xff0c;本质上就是一个 function 处理函数&#xff0c;Express中间件的格式如下: 注意:中间件函数的形参列表中&#xff0c;必须包合 next 参数。而路由处理函数中只包含 req 和 res。 // 常量 mw 所指向的&#xff0c;就是一个中间件函数…

WorkPlus稳定服务助力行业千万用户,打造无界沟通协作平台

在企业移动数字化领域&#xff0c;WorkPlus以其十年如一日的研发实力和千万级用户案例&#xff0c;成为众多企业首选的移动数字化平台。究竟是什么样的力量支撑着WorkPlus在市场上占据如此重要的地位呢&#xff1f;接下来&#xff0c;让我们一起揭开WorkPlus的神秘面纱&#xf…