进程间通信之共享内存(简单介绍消息队列和信号量)(1)

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

system V共享内存


作用:用于多个进程间数据共享

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

原理:开辟出一块物理内存地址,然后多个进程都映射到自己的虚拟地址空间中,通过虚拟地址直接访问物理内存中的数据

image.png

相当于是进程直接看到的数据。举个例子,管道就是从写端的数据拷贝到管道缓冲区,再从管道缓冲区拷贝到自己的进程空间,相对于共享内存是多了两次拷贝


共享内存示意图


image.png

常见的共享内存操作


image.png


共享内存数据结构


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 */
};

共享内存函数


shmget函数


功能:用来创建共享内存

原型

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

参数

 key:这个共享内存段名字

 size:共享内存大小,一般是PAGE_SIZE的整数倍(4096字节)

 shmflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的

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


shmflg: IPC CREAT | IPC EXCL | 0664


IPC_ CREAT

 如果共享内存不存在则创建打开,若已经存在则直接打开

IPC_ EXCL

 与IPC_ CREAT搭配使用,共享内存不存在则创建打开,若存在则报错返回 ,一个程序只能启动一次的程序

mode_ flags

 共享内存的访问权限0664


shmat函数


功能:

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

原型

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

参数

shmid: 共享内存标识 shmaddr:指定连接的地址

shmflg:它的两个可能取值是SHM_RND和SHM_RDONLY(只读,前提是具备读的权限)

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


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

image.png


注意:这里常用的是IPC_RMID,但是并非直接删除,而是做一个标记,删除最终还是由操作系统进行


这里我们思考一个问题:

多个进程,访问同一个共享内存,突然有一个进程要删除了共享内存,如何避免其他进程不会出现错误呢?

其实共享内存是有个当前的映射连接计数(表示现在有多少进程正在访问)所以这里的RMID叫做标记删除,并不是真的删除,而是标记一下, 被标记的共享内存将不再接受新的映射而是等当前的映射连接计数为0时,再实际删除删除由系统完成,进程所做的删除操作,其实只是标记一下。


简单举例:

image.png

举例2

测试代码结构

# ls
client.c comm.c comm.h Makefile server.c
# cat Makefile
.PHONY:all
all:server client
client:client.c comm.c
gcc -o $@ $^
server:server.c comm.c
gcc -o $@ $^
.PHONY:clean
clean:
rm -f client server

comm.h

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



目录
相关文章
|
27天前
麒麟系统mate-indicators进程占用内存过高问题解决
【10月更文挑战第7天】麒麟系统mate-indicators进程占用内存过高问题解决
119 2
|
2月前
|
存储 Linux 调度
深入理解操作系统:从进程管理到内存分配
【8月更文挑战第44天】本文将带你深入操作系统的核心,探索其背后的原理和机制。我们将从进程管理开始,理解如何创建、调度和管理进程。然后,我们将探讨内存分配,了解操作系统如何管理计算机的内存资源。最后,我们将通过一些代码示例,展示这些概念是如何在实际操作系统中实现的。无论你是初学者还是有经验的开发者,这篇文章都将为你提供新的视角和深入的理解。
|
1月前
|
缓存 算法 调度
深入浅出操作系统:从进程管理到内存优化
本文旨在为读者提供一次深入浅出的操作系统之旅。我们将从进程管理的基本概念出发,逐步深入到内存管理的复杂世界,最终探索如何通过实践技巧来优化系统性能。文章将结合理论与实践,通过代码示例,帮助读者更好地理解操作系统的核心机制及其在日常技术工作中的重要性。无论你是初学者还是有一定经验的开发者,这篇文章都将为你打开一扇通往操作系统深层次理解的大门。
|
29天前
麒麟系统mate-indicators进程占用内存过高问题解决
【10月更文挑战第5天】麒麟系统mate-indicators进程占用内存过高问题解决
107 0
|
2月前
|
监控 Ubuntu API
Python脚本监控Ubuntu系统进程内存的实现方式
通过这种方法,我们可以很容易地监控Ubuntu系统中进程的内存使用情况,对于性能分析和资源管理具有很大的帮助。这只是 `psutil`库功能的冰山一角,`psutil`还能够提供更多关于系统和进程的详细信息,强烈推荐进一步探索这个强大的库。
41 1
|
2月前
|
缓存 Linux C语言
C语言 多进程编程(六)共享内存
本文介绍了Linux系统下的多进程通信机制——共享内存的使用方法。首先详细讲解了如何通过`shmget()`函数创建共享内存,并提供了示例代码。接着介绍了如何利用`shmctl()`函数删除共享内存。随后,文章解释了共享内存映射的概念及其实现方法,包括使用`shmat()`函数进行映射以及使用`shmdt()`函数解除映射,并给出了相应的示例代码。最后,展示了如何在共享内存中读写数据的具体操作流程。
|
2月前
|
Linux C语言
C语言 多进程编程(七)信号量
本文档详细介绍了进程间通信中的信号量机制。首先解释了资源竞争、临界资源和临界区的概念,并重点阐述了信号量如何解决这些问题。信号量作为一种协调共享资源访问的机制,包括互斥和同步两方面。文档还详细描述了无名信号量的初始化、等待、释放及销毁等操作,并提供了相应的 C 语言示例代码。此外,还介绍了如何创建信号量集合、初始化信号量以及信号量的操作方法。最后,通过实际示例展示了信号量在进程互斥和同步中的应用,包括如何使用信号量避免资源竞争,并实现了父子进程间的同步输出。附带的 `sem.h` 和 `sem.c` 文件提供了信号量操作的具体实现。
|
2月前
|
Linux Windows
检测进程内存的活跃程度
检测进程内存的活跃程度
|
2月前
|
Linux
查看进程的内存使用信息
查看进程的内存使用信息
|
3月前
|
开发者 API Windows
从怀旧到革新:看WinForms如何在保持向后兼容性的前提下,借助.NET新平台的力量实现自我进化与应用现代化,让经典桌面应用焕发第二春——我们的WinForms应用转型之路深度剖析
【8月更文挑战第31天】在Windows桌面应用开发中,Windows Forms(WinForms)依然是许多开发者的首选。尽管.NET Framework已演进至.NET 5 及更高版本,WinForms 仍作为核心组件保留,支持现有代码库的同时引入新特性。开发者可将项目迁移至.NET Core,享受性能提升和跨平台能力。迁移时需注意API变更,确保应用平稳过渡。通过自定义样式或第三方控件库,还可增强视觉效果。结合.NET新功能,WinForms 应用不仅能延续既有投资,还能焕发新生。 示例代码展示了如何在.NET Core中创建包含按钮和标签的基本窗口,实现简单的用户交互。
66 0