当前位置:网站首页>进程间通信-共享内存shmat
进程间通信-共享内存shmat
2022-06-12 23:47:00 【喵小林菌】
进程间通信-共享内存shmat
进程间通信三种方式
在linux系统中,每个进程都有独立的虚拟空间地址,通过MMU地址转换将虚拟地址与物理地址进行映射,每个进程相同的虚拟地址空间都会映射到不同的物理地址,每个进程在物理内存空间都是相互独立和隔离的。
不同的进程之间如果需要相互通信,该怎么办?因为不同的进程在物理内存上是相互隔离的,所以需要借助第三方工具来完成进程间通信。其实进程间通信的本质就是交换数据,进程间交换数据有三种方式:通过文件、通过内核、共享内存。
- 通过文件:AB进程通过访问同一个磁盘文件(I/O访问)进行数据交换
- 通过内核:进程间用户空间是相互独立,但是内核空间都是同一个, 因此可以通过内核这个中介去进行数据交换
- 共享内存:每个进程间的虚拟地址会映射到不同的物理地址,如果允许映射到同一块物理地址就可以进行数据交换
共享内存特点
- 共享内存 VS 通过文件:共享内存读写速度更快
- 共享内存VS通过内核:抛弃了内核“代理人”角色,让两个进程直接通过一块内存通信。减少了内存拷贝(从用户拷贝到内核、从内核拷贝到用户空间),减少了2次系统调用,提高系统性能
- 共享内存缺点:是共享内存并未提供同步机制,所以需要用其他机制来同步对共享内存的方位,这将由程序员来完成。一般可以通过信号量、互斥锁、文件锁等配合使用,防止数据的踩踏。
共享内存原理
共享内存是由IPC为进程创建的一个特殊的地址范围,出现在该进程的地址空间中,其他进程可以将同一段共享内存连接到他们自己的地址空间中。所有进程都可以访问共享内存中的地址,就好像他们是由malloc分配的一样。如果一个进程向共享内存中写了数据,那么其他进程将立刻能够看到。
共享内存使用
创建/获取共享内存shmget
该函数用来创建/获取共享内存
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
- key:IPC 对象的键值,一般为IPC_PRIVATE或ftok返回的key值
- size:共享内存的大学,一般为存物理页的整数倍
- shmflg:IPC_CREAT:如果不存在与制定的key对应的段,那么就创建一个新段;IPC_EXCL:若key制定的内存存在且制定了IPC_CREAT,返回EEXIST错误;
- 返回值:共享内存的标识符ID
映射共享内存shmat
该函数将shmid标识的共享内存引入到当前进程的虚拟地址空间
#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
- shmid:共享内存的IPC对象ID
- shmaddr:若为NULL:共享内存会被attach到一个合适的虚拟地址空间,建议使用NULL;不为NULL:系统会根据参数及地址边界对齐等分配一个合适的地址
- shmflg:IPC_RDONLY:附加只读权限,不指定的话默认是读写权限;IPC_REMAP:替换位于shmaddr处的任意既有映射:共享内存段或内存映射;
- 返回值:共享内存段的地址
共享内存读写
共享内存的读写就要注意共享内存多进程访问同步,一般可以通过信号量、互斥锁、文件锁等配合使用,防止数据的踩踏。
解除内存映射shmdt
该函数解除内存映射,将共享内存分离出当前进程的地址空间
#include <sys/types.h>
#include <sys/shm.h>
int shmdt(const void *shmaddr);
- shmaddr:共享内存地址
注意,函数shmdt仅仅是使进程和共享内存脱离关系,将共享内存的引用计数减1,并为删除共享内存。通过#ipc -m就可查看某个IPC对象的状态,其中“连接数”就是表示该共享内存对象被引用的计数。
删除共享内存
上面看到,shmdt仅仅是使进程和共享内存脱离关系,并未删除共享内存。当共享内存的引用次数未0,可以调用shmctl的IPC_RMID命令才会删除共享内存。或者进程结束后,也会被删除掉。
shmctl获取/设置共享内存对象属性
#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
- shmid:共享内存的对象ID
- cmd:IPC_RMID:删除共享内存段及关联的shmid_ds数据结构
- buf:指向包含共享模式和访问权限的结构
- 返回值:成功返回0,失败返回-1
更多的cmd可以通过man shmct去查看。
生产者-消费者代码示例
下面是一个简单的生产者-消费者模型,生产者producer进程负责将用户输入的数据写到共享内存中,消费者customer进程负责将共享内存中的读出来并打印出来。下面的程序示例通过共享内存中的变量written_by_you标记进行一个读写的同步,保证读写操作是互斥的。
//share.h
#define TEXT_SZ 2048
struct shared_use_st
{
int written_by_you;
char some_text[TEXT_SZ];
};
//customer.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include "share.h"
int main()
{
int running = 1;
void *shared_memory = (void *)0;
struct shared_use_st *shared_stuff;
int shmid;
srand((unsigned int)getpid());
shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666 | IPC_CREAT);
if (shmid == -1)
{
fprintf(stderr, "shmget failed\n");
exit(EXIT_FAILURE);
}
shared_memory = shmat(shmid, (void *)0, 0);
if (shared_memory == (void *)-1) {
fprintf(stderr, "shmat failed\n");
exit(EXIT_FAILURE);
}
printf("Memory attached at %X\n", (int)shared_memory);
shared_stuff = (struct shared_use_st *)shared_memory;
shared_stuff->written_by_you = 0;
while(running)
{
if (shared_stuff->written_by_you)
{
printf("You wrote: %s", shared_stuff->some_text);
sleep( rand() % 4 );
shared_stuff->written_by_you = 0;
if (strncmp(shared_stuff->some_text, "end", 3) == 0)
{
running = 0;
}
}
}
if (shmdt(shared_memory) == -1)
{
fprintf(stderr, "shmdt failed\n");
exit(EXIT_FAILURE);
}
if (shmctl(shmid, IPC_RMID, 0) == -1)
{
fprintf(stderr, "shmctl(IPC_RMID) failed\n");
exit(EXIT_FAILURE);
}
printf("customer exit.\n");
exit(EXIT_SUCCESS);
}
//producer.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include "share.h"
int main()
{
int running = 1;
void *shared_memory = (void *)0;
struct shared_use_st *shared_stuff;
char buffer[BUFSIZ];
int shmid;
shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666 | IPC_CREAT);
if (shmid == -1)
{
fprintf(stderr, "shmget failed\n");
exit(EXIT_FAILURE);
}
shared_memory = shmat(shmid, (void *)0, 0);
if (shared_memory == (void *)-1)
{
fprintf(stderr, "shmat failed\n");
exit(EXIT_FAILURE);
}
printf("Memory attached at %X\n", (int)shared_memory);
shared_stuff = (struct shared_use_st *)shared_memory;
while(running)
{
while(shared_stuff->written_by_you == 1)
{
sleep(1);
printf("waiting for client...\n");
}
printf("Enter some text: ");
fgets(buffer, BUFSIZ, stdin);
strncpy(shared_stuff->some_text, buffer, TEXT_SZ);
shared_stuff->written_by_you = 1;
if (strncmp(buffer, "end", 3) == 0)
{
running = 0;
}
}
if (shmdt(shared_memory) == -1)
{
fprintf(stderr, "shmdt failed\n");
exit(EXIT_FAILURE);
}
printf("producer exit.\n");
exit(EXIT_SUCCESS);
}
参考资料
[1]嵌入式C语音自我修养,王立涛
[2]大连理工大学《嵌入式软件设计》慕课
边栏推荐
- 实战 | UI 自动化测试框架设计与 PageObject 改造
- 21 Chundong University blasting safety online peacetime operation 123 [standard answer]
- Test platform series (97) perfect the case part
- CS for mobile security [nethunter]
- Memory address mapping of u-boot
- Theory + practice will help you master the dynamic programming method
- OSM地图本地发布-如何生成各省市矢量地图
- How to get Matplotlib figure size
- Comprehensive analysis of C array
- NCF 的Dapr应用实例的运行
猜你喜欢
Video tracker error troubleshooting
H5时代leaflet中还在用DivIcon?
Based on three JS offshore wind power digital twin 3D effect
The Milvus graphical management tool Attu is coming!
SAP QM qp03 displays an inspection plan with multiple specs inspection features
线上真实排队系统重构案例分享——实战篇
Leetcode 2164. 对奇偶下标分别排序(可以,一次过)
[matlab] two dimensional curve
QT actual combat case (38) -- using qpprocess class to realize the function of starting process
2022年危險化學品經營單比特安全管理人員考試試題及在線模擬考試
随机推荐
华为云弹性云服务器ECS使用【华为云至简致远】
[literature translation - Part] revealing the structure of clinical EEG signals by self supervised learning (SSL and RP principles / data / preprocessing)
The programmer has worked for 7 years. At the age of 31, he has no choice but to deliver takeout. I really don't want you to go through his journey again
OSM map local publishing - how to generate vector maps of provinces and cities
KConfig
Pytorch loading model error resolution
CS for mobile security [nethunter]
Examination questions and online simulation examination for safety management personnel of hazardous chemical business units in 2022
2022年危险化学品经营单位安全管理人员考试试题及在线模拟考试
【Matlab】矩阵
H5时代leaflet中还在用DivIcon?
Accelerating with Dali modules
Using baserecyclerviewadapterhelper to implement tree structure
NCF 的Dapr应用实例的运行
Hongmeng starts
Dry goods sharing | BitSet application details
Modify the text color of the menu on the right of toobar
Save state when viewpager is used with fragment fragmentpageradapter
Lower interest rates lead to higher bond prices
leaflet如何优雅的展示重叠点位的气泡窗口