江立 陆志恩
摘 要:在Linux系统中两个或多个进程间通信,是实现计算机内部传递信息的机制,它们之间是同步的关系,多个协作进程间完成数据的共享、消息的交换。文章基于Ubuntu 12操作系统环境,通过共享内存通信的方式设计一种基于多进程的同步关系,它们共享内存的同步通信机制。文章详细描述了该机制的设计原理和实现方式,并采用内核文件shm.h实现了进程同步,通过内存片段共享机制减少多个进程之间的切换时间,实现了共享内存在多进程间的高效通信。
关键词:PV操作;协作进程;共享内存;互斥信号量
中图分类号:TP311 文献标识码:A 文章编号:2096-4706(2023)18-0125-04
Research on the Application of Shared Memory in Efficient Inter Process Communication
JIANG Li, LU Zhien
(Nanfang College Guangzhou, Guangzhou 510970, China)
Abstract: In a Linux system, communication between two or more processes is a mechanism for transmitting information within a computer. The relationship among them is synchronous, and data sharing and message exchange is completed among multiple collaborative processes. This paper is based on the Ubuntu 12 operating system environment and designs a synchronization relationship based on multiple processes through shared memory communication. They share a synchronous communication mechanism in memory. This paper provides a detailed description of the design principle and implementation method of this mechanism, and uses the kernel file shm.h to achieve process synchronization. Through the memory fragment sharing mechanism, the switching time among multiple processes is reduced, achieving efficient communication of shared memory among multiple processes.
Keywords: PV operation; collaborative process; shared memory; mutex semaphore
0 引 言
Linux操作系統,目前版本很多,像Ubuntu系统、Red Hat Linux操作系统等,它们是免费的,同时是一种类UNIX操作系统。Linux有上百种不同的发行版,如基于商业开发的Oracle Linux、SUSE和基于社区开发的debian、archlinux等。Red Hat Linux可以在不同的硬件平台上安装和运行,例如SPARC等处理器的平台。选择好的系统开发环境是安全软件保证和网络安全保障的重要方面,Linux因其健壮性和稳定性等特点,越来越显示出它在控制领域、通信领域、军事领域、网络传输领域的优越性。进程通信是指进程之间的信息交换,本文根据Linux系统中共享内存概念和原理,研究了一种进程通信的方法。此方法的研究和在投入使用,能提供一种高效安全的通信机制。
1 进程间通信类别
进程间通信就是在不同进程之间传播或交换信息,它提供了一组编程接口,程序员和研究者能够协调不同的进程,
使它们在一个操作系统里同时运行,并相互传递、交换信息。Linux中进程间通信方式通常有以下四种:
1)消息队列:进程间采用消息队列方式时,以消息Message为单位。消息队列在数据结构里面是一链表,用来存贮接收到的信息,可以理解为一个缓存区,当然也是一种临界资源。在网络传输中,计算机网络中发送的“报文”就是一种格式化的消息,这个报文数据方面在数据链路层传输。进程通过操作系统提供的发送原语“Send message”,接受原语“Accept the news”,利用两组原语进行数据交换。
2)信号量:即是Semaphore,采用PV操作实现进程的同步和互斥,P操作代表进程向Linux申请一个单位资源,V操作代表释放一个单位资源。这样能够保证两个或多个关键代码段不被并发调用。操作系统采用信号量完成这个过程,第一部需要创建信号量S,将P操作S以及V操作S,分别放置在每个关键代码段的首末端,Linux操作系统中P操作是申请资源,V操作是释放资源。
定义:typedef struct{int value;信号量值struct process_control block*l信号量等待队列指针}semaphore。
3)管道通信:UNIX中管道是一种pipe文件,这个文件可以保存大量的信息,管道的一端连接读进程,另外一端链接写进程。进程通信采用pipe通信方式时,Linux会在内存中开辟的一个大小固定的缓冲区,读进程和写进程需要按照“管道”的规则通信,管道在Linux操作系统中是一种半双工通信,在一段时间间隔中只能实现单向的数据传输。
4)共享内存:进程通信采用共享内存方式时,LINUX在内存中开辟一块共享空间,允许通信进程对其互斥的访问。
例如两个进程,一个写进程A,一个读进程B,它们进程对共享空间的访问必须是互斥的,在一段时间间隔内,进程A只允许读该共享空间,进程B只允许写该共享空间。互斥访问可以通过PV操作实现。
2 共享内存通信原理
在Linux进程通信过程中,每个进程都有自己的进程控制快,简称为PCB,Linux进程在自己的生命周期中有地址空间,需要一个对应的页表,进程的逻辑地址和物理地址是一一对应的,所以这样形成进程的虚拟地址与物理地址映射,并且通過内存管理MMU单元进行管理。在操作系统的底层,两个不同的虚拟地址,进程地址空间如图1所示,通过页表映射到相同的一个物理地址区域,它们所指向的区域称为共享内存。
多个进程以共享内存机制,在Ubuntu 14操作系统里面,实现进程间通信,通常来说采用下面的步骤:
消费者进程:
1)OS创建一个共享的内存片段,在Linux或者Windows系统内部,内存区域有m个大小的块区域。
2)OS中对同一个内存片段,用PV操作来实现,多个进程间可以互斥访问数据块。
3)在Linux中等待信号,直到当前块可读。
4)多个进程从内存片段中读取该内存块的信息。
5)转到步骤st3)。
生产者进程:
1)生产者进程P1,P2,P3,…,PN打开命名的共享内存。
2)进程接收等待信号,生产者将信息写入当前内存块。
3)产者进程P1,P2,P3,…,写数据到内存块。
4)OS发出信号,代表消费者可读内存片段当前的数据块。
5)进程继续并发执行,转入上面st2。
3 共享内存结构设计
在Ubuntu 12操作系统中,如果有M个进程,同时进行共享内存读写操作,对共享内存中的区域数据,必须利用PV原语设置好,在操作系统的不同的环境中,实现线程互斥和同步机制。Ubuntu 12操作系统环境中,对于内存区域块X,先解决的就是如何组织内存块,生产者进程将数据写入到内存块,新创建的消费者进程,采用于正在处理内存的数据。多进程共享内存通信结构体,如图2所示。
Linux提供了一系列API来操作共享内存。创建共享内存成功,下面函数成功,则返回标识符,如果函数调用不成功否则-1。
int shmget(int , int size, int shmflg);权限对共享内存非常有用,利用这个功能,提供一种有效的对数据进行只读访问的方法,为避免数据被其他用户修改,通过将数据放入共享内存并设置它的权限。
附加到共享内存函数,*shmat函数如果调用成功,在Linux系统中,*shmat返回一个指针,指向内存片段中的第一个字节;在函数调用成功的时候,如果*shmat返回-1,代表void *shmat(int shm_id, int shmflg , const void *shm_addr);的含义是失败。UNIX内部机制,建立一种方法,将这一段内存映射到进程虚拟地址空间,这样,新产生的进程。方便可以对共享的内存片段进行访问。
int shmdt(const void *shm_addr);UNIX系统设置了一种机制,int shmdt函数将共享内存从当前进程中分离。该函数有2种返回结果,如果返回-1,int shmctl(int shm_id, int cmd, struct shmid_ds *buf);控制共享内存的函数,它比信号量要简单很多。断开共享内存链接,代表失败。如果为0,代表返回成功。需要说明的是这个进程无法再访问它,并不是说共享内存已被销毁。
4 内存读写与同步
4.1 生产者进程写数据入内存
按照设计的共享内存机制,编写仿真程序Client.c。生产者进程是使用存在的共享内存、连接共享内存、向共享内存中写入内容、断开联系、释放内存。written_by_you标志来判断消费者是否已经将原先的数据处理完成,如果没有则等待;如果已经处理完则从键盘读入字符串写入共享内存。当输入为end时,程序结束。
Void write(){
shared_memory = shmat(shmid, NULL, 0);
if(memory==-1) {
//提示内存分配错误 printf( "内存分配错误\n");
exit(0);
}
printf("memory %X\n", (int)memory);
stuff->by_you = 0;
//结构体数据变量 stuff = (struct shared_use_st *)memory;
//循环条件判断 while(ruing){{ {
if(stuff->_by_you) {
//提示写入内存片段 printf("写内存片段: %s", stuff->s_text);
//休眠函数 sleep(rand()%6);
stuff->by_you = 0;
if(strncmp(stuff->s_text, "end", 6)==0) {
running = 0;
}}}
}
}
}
在生产者进程写入的过程模块,循环函数while,逻辑变量running为真,表示的含义是获得可以写入的数据块,written_by_you共享变量,设定进程的同步机制,written_by_you可用时候,轮到生产者,把数据写入共享内存,在Linux环境或者Windows环境,都是适用的,接着通过strncmp函数对数据字节比较,得到的结果进行分析,通过进程的通知消息,最终end通知进程写操作完成,这样同步进程,消费者进程可以对内存片段进行读了。
4.2 消费者进程读数据
按照内存共享机制编写Server.c。消费者进程是创建共享内存、连接共享内存,从共享内存中读取内容、断开联系、释放内存。
Void read(){
memory = shmat(shmid, NULL, 0);
if(memory==-1) {
//提示内存分配错误 printf("内存分配错误\n");
exit(0);
}
printf("memory %X\n", (int)memory);
//使用结构体变量 stuff = (struct sha_use_st *)memory;
while(ruing) {
while(stuff->written_by_you==1) {
//休眠100毫秒 sleep(100);
fprintf("等待写入数据...\n");
}
printf("写数据: ");
//准备写入数据 fgets(buffer, BUFSIZ, stdin);//内存拷贝
//准备拷贝数据 strncpy(stuff->s_text, buffer, TEXT_SZ);
//设置其值为1 stuff->by_you = 1;
if(strncmp(buffer, "stop", 4)==0) {
running =0;
}
}}
从read函数可知,读操作和写操作基本一致,written_by_you以判断有没有新的数据写入。如果有,则输出,并且等待一个随机的时间再将written_by_you重置为0。等待一个随机时间的目的是模拟程序在对数据做复杂的处理,在此期间,生产者程序必须等待,不能写入新的数据。当传递的字符串为“end”时则程序结束。
4.3 功能测试
在Intel(R) Core(TM) i5-10210U CPU @ 1.60 GHz,8 GB内存的笔记本中,操作系统采用Ubuntu 14,VMware Workstation 12,语言环境C语言,编程测试。从客户端每次写入10~20个Bytes的数据到共享的内存片段,消费者进程然后从服务器端读出数据,测试每次从内存中读取的字节内容,从测试结果可以得出,实现了同步读取内存片段的内容。在测试环境中,同时可以建立多个消费者进程读操作。多进程间通信如图3所示。
5 效果分析
在Ubuntu 14操作系统实验环境中,./server &作為一个后台进程启动,进程端口号3301,在实际的运行中,多个进程共享的内存片段是D5832000,客户端进程通过gcc-o编译成功后,运行客户端进程,输入“I love you”,服务器端立即读出这个字符串,这样完成了2个进程的协作关系。读取同一片内存空间,从测试结果可以得出,实现了同步读取内存片段的内容。在测试环境中,同时可以建立多个消费者进程读操作,“wait for the client”。
6 结 论
基于Linux或UNIX系统,本课题依据操作系统中共享内存概念和原理,设计了一种多进程共享内存的同步通信机制,在数据的仿真实验方面,采用Linux内核文件shm.h实现进程同步和安全,通过内存片段共享机制,能够减少多个进程间的切换时间,对比前面介绍的四种进程间的通信方式,比其他进程通信方式和关键区等线程同步技术相对比,在LINUX开源环境中,解决了共享内存在多进程间的高效通信。通过实验仿真,完成了服务器端和客户端进程的同步机制。
参考文献:
[1] TSAI Y R,KO J H. Implementation of a Portable Multi-channel EMG Signal Detection System for Android-based Smartphones by Using USB-OTG Interface[C]//2018 IEEE International Conference on Applied System Invention(ICASI).Chiba:IEEE,2018:766-769.
[2] 李小群,赵慧斌,孙玉芳.进程间通信机制的分析与比较 [J].计算机科学,2002(11):16-21.
[3] 周伟明.多核计算与程序设计 [M].武汉:华中科技大学出版社,2009
[4] RICHITER J.Windows核心编程 [M].王建华,张焕生,侯丽坤,等译.北京:机械工业出版社,2000.
[5] 杨倩,杨明赵. Android显示服务器——SurfaceFlinger研究 [J].计算机应用与软件,2014,31(6):324-326.
[6] 凌大鹏,陆平,李芳,等.基于Win32 API进程通信的方法研究 [J].舰船防化,2008(6):48-52.
[7] 杨宁学,诸昌钤,聂爱丽.内存映射文件及其在大数据量文件快速存取中的应用 [J].计算机应用研究,2004(8):187-188.
[8] 马魁涛,蔡颖,郭宝峰.Win32进程间信息共享的实现方法研究 [J].计算机应用与软件,2007(12):119-120+157.
[9] PAN K. A Hybrid HLA Time Management Algorithm Based on Both Conditional and Unconditional Information [J].Simulation,2009,85(9):559-573.
[10] GRANDE R E D,BOUKERCHE A. Dynamic balancing of communication and computation load for HLA-based simulations on large-scale distributed systems [J].Journal of Parallel and Distributed Computing,2011,71(1):40-52.
作者简介:江立(1984—),男,汉族,湖北武汉人,讲师,硕士研究生,主要研究方向:软件工程、无线传感器网络;陆志恩(1979—),男,汉族,广东广州人,讲师,博士研究生,研究方向:凝聚态物理。