利用共享内存实现进程间通信--简单剪贴板实例
利用共享内存,实现进程间高效率数据共享

利用共享内存,实现进程间高效率数据共享摘要:CPU速度比内存更快,内存中的缓存是用来解决CPU和内存速度差异的。
多个模块都可以访问内存缓冲区,据此可以实用内存来实现进程间的数据共享。
本文在Unix环境下实现该技术。
关键字:共享内存多进程文件映射Abstract: CPU speed faster than the memory, the cache memory is used to solve the CPU and memory speed differences. Multiple modules can access memory buffer, accordingly can realize between memories to practical process data sharing based on UNIX environment to realize this technology.Key Word: shared memory, processes, file mapping一、Windows系统中的共享内存的概念共享内存是在不同进程间可共享的内存块,是通过将同一块物理内存映射到不同进程地址空间中的方法,实现数据在内存中直接被不同进程共享。
共享内存在几乎所有的操作系统中都存在,是进程间共享数据最高效的方法。
在Windows操作系统中,共享内存是通过文件映射来使用。
文件映射按共享方式可分为命名文件映射和非命名文件映射,按底层文件支持方式,又可分为有文件支持的文件映射和无文件支持的文件映射。
命名文件映射指在创建文件映射时,为该文件映射提供一个名称,其它进程需要使用该文件映射时,通过该名称打开已经存在的文件映射。
为文件映射起名时要注意,如果是在安装了终端服务器的服务器操作系统上,需要指定\\Global\或\\Local\名称前缀,指示是全局名称还是当前用户会话范围的名称。
有底层文件支持的文件映射在创建文件映射时,为文件映射提供一个打开的文件句柄,该文件映射将对应使用提供的文件。
进程实验-进程间通信(管道、消息、共享内存、软中断)

进程实验3 Linux 进程间通信一、软中断信号的处理,实现同一用户的各进程之间的通信。
●相关的系统调用⏹kill(pid ,sig):发送信号⏹signal(sig, func):指定进程对信号sig的处理行为是调用函数func。
●程序清单#include <unistd.h>#include <stdio.h>#include <signal.h>void waiting();void stop();int wait_mark;main(){int p1,p2;while((p1=fork())==-1);if(p1>0){while((p2=fork())==-1);if(p2>0){ printf("parent\n");/*父进程在此完成某个操作、或接收到用户从键盘输入的特殊按键命令后发出下面的信号。
这里省略。
*/kill(p1,16);kill(p2,17);wait(0);wait(0);printf("parent process id killed! \n");exit(0);}else/* p2==0*/{printf("p2\n");wait_mark=1;signal(17,stop);waiting();printf("child process 2 is killed by parent! \n");exit(0);}}else/*p1==0*/{printf("p1\n");wait_mark=1;signal(16,stop);waiting();printf("child process 1 is kelled by parent! \n");exit(0);}}void waiting(){while(wait_mark!=0);}void stop(){wait_mark=0;}●输入并运行此程序,分析程序的运行结果。
Linux进程间通信 共享内存

Linux进程间通信共享内存共享内存(Shared Memory)共享内存区域是被多个进程共享的一部分物理内存。
如果多个进程都把该内存区域映射到自己的虚拟地址空间,则这些进程就都可以直接访问该共享内存区域,从而可以通过该区域进行通信。
共享内存是进程间共享数据的一种最快的方法,一个进程向共享内存区域写入了数据,共享这个内存区域的所有进程就可以立刻看到其中的内容。
这块共享虚拟内存的页面,出现在每一个共享该页面的进程的页表中。
但是它不需要在所有进程的虚拟内存中都有相同的虚拟地址。
图共享内存映射图象所有的System VIPC对象一样,对于共享内存对象的访问由key控制,并要进行访问权限检查。
内存共享之后,对进程如何使用这块内存就不再做检查。
它们必须依赖于其它机制,比如System V的信号灯来同步对于共享内存区域的访问。
每一个新创建的共享内存对象都用一个shmid_kernel数据结构来表达。
系统中所有的shmid_kernel数据结构都保存在shm_segs向量表中,该向量表的每一个元素都是一个指向shmid_kernel数据结构的指针。
shm_segs向量表的定义如下:struct shmid_kernel*shm_segs[SHMMNI];SHMMNI为128,表示系统中最多可以有128个共享内存对象。
数据结构shmid_kernel的定义如下:struct shmid_kernel{struct shmid_ds u;/*the following are private*/unsigned long shm_npages;/*size of segment(pages)*/unsigned long*shm_pages;/*array of ptrs to frames-SHMMAX*/struct vm_area_struct*attaches;/*descriptors for attaches*/};其中:shm_pages是该共享内存对象的页表,每个共享内存对象一个,它描述了如何把该共享内存区域映射到进程的地址空间的信息。
使用Windows共享内存技术 实现Python与CC++程序间的数据传递

◎研动态旷"使用Windows共哮内存毎术实现Python与C/C卄程序|聖叙樹递梁斌I臨沁J,)療敷療錨莎Python是一门高级编程语言,它具有简单易懂、开发效率高的优点。
但是在使用Python语言编程的过程中,包括进行RPLIDAR数据通讯和解析时,发现单个工作周期的时长达到了0.4~0.5s,造成采样频率过低,严重影响了最终计算结果的准确度。
通过对程序各模块进行分析、测试,发现绝大部分时间都消耗在与RPLI-DAR的数据通讯和解析上,每读取1个周期(360。
)的数据要耗时0.4s左右,大大降低了程序的执行速率。
为了进行耗时对比分析,又使用C++语言编程,并通过调用RPLIDAR的SDK 开发库,完成与RPLIDAR的数据通讯和解析,发现速度明显提升,读取、解析1个周期的数据只需要0.08-0.12s,仅为Python程序的1/4左右。
经过原因分析,发现执行Python程序时,首先会将.py文件中的源代码通过Python解释器翻译成byte code(字节码),然后再由Python Virtual Machine(Python虚拟机)去执行编译好的byte code;而C/C++语言编译完后就是可直接在处理器上运行的机器码。
因此相比C/C++而言,Python的运行速度比较慢。
鉴于此,我们可以用C/C++编写需要频繁运行且耗时较长的底层应用程序,而用Python完成数据存储、应用、展示等上层部分,同时使用共享内存技术实现不同应用之间的数据传递。
本文进行总结。
方案及其实施解决方案针对应用程序对快速响应与数据处理的实际需求,给出解决方案:(1)用C卄语言编写RPLIDAR数据通讯、解析程序。
由于此类应用的运算量大、耗时长,对运行速度要求高,因此,使用运行速度更快的C++语言来完成,以满足程序对速度的要求,并将运算结果按照一定格式写入共享内存块中。
(2)用Python语言编写数据后期处理功能模块。
linux进程间的通信(C):共享内存

linux进程间的通信(C):共享内存⼀、共享内存介绍共享内存是三个IPC(Inter-Process Communication)机制中的⼀个。
它允许两个不相关的进程访问同⼀个逻辑内存。
共享内存是在两个正在进⾏的进程之间传递数据的⼀种⾮常有效的⽅式。
⼤多数的共享内存的实现,都把由不同进程之间共享的内存安排为同⼀段物理内存。
共享内存是由IPC为进程创建⼀个特殊的地址范围,它将出现在该进程的地址空间中。
其他进程可以将同⼀段共享内存连接它们⾃⼰的地址空间中。
所有进程都可以访问共享内存中的地址,就好像它们是由malloc分配的⼀样。
如果某个进程向共享内存写⼊了数据,所做的改动将⽴刻被可以访问同⼀段共享内存的任何其他进程看到。
⼆、共享内存的同步共享内存为在多个进程之间共享和传递数据提供了⼀种有效的⽅式。
但是它并未提供同步机制,所以我们通常需要⽤其他的机制来同步对共享内存的访问。
我们通常是⽤共享内存来提供对⼤块内存区域的有效访问,同时通过传递⼩消息来同步对该内存的访问。
在第⼀个进程结束对共享内存的写操作之前,并⽆⾃动的机制可以阻⽌第⼆个进程开始对它进⾏读取。
对共享内存访问的同步控制必须由程序员来负责。
下图显⽰了共享内存是如何共存的:图中的箭头显⽰了每个进程的逻辑地址空间到可⽤物理内存的映射关系。
三、共享内存使⽤的函数1. #include <sys/shm.h>2.3. int shmget(key_t key, size_t size, int shmflg);4. void *shmat(int shm_id, const void *shm_addr, int shmflg);5. int shmdt(const void *shm_addr);6. int shmctl(int shm_id, int cmd, struct shmid_ds *buf);1. shmget函数该函数⽤来创建共享内存:1. int shmget(key_t key, size_t size, int shmflg);参数:key : 和信号量⼀样,程序需要提供⼀个参数key,它有效地为共享内存段命名。
Linux下进程间通信--共享内存:最快的进程间通信方式

Linux下进程间通信--共享内存:最快的进程间通信⽅式共享内存:⼀、概念:共享内存可以说是最有⽤的进程间通信⽅式,也是最快的IPC形式。
两个不同进程A、B共享内存的意思是,同⼀块物理内存被映射到进程A、B各⾃的进程地址空间。
进程A可以即时看到进程B对共享内存中数据的更新,反之亦然。
由于多个进程共享同⼀块内存区域,必然需要某种同步机制,互斥锁和信号量都可以。
采⽤共享内存通信的⼀个显⽽易见的好处是效率⾼,因为进程可以直接读写内存,⽽不需要任何数据的拷贝。
对于像管道和消息队列等通信⽅式,则需要在内核和⽤户空间进⾏四次的数据拷贝,⽽共享内存则只拷贝两次数据[1]:1.⼀次从输⼊⽂件到共享内存区,2.另⼀次从共享内存区到输出⽂件。
实际上,进程之间在共享内存时,并不总是读写少量数据后就解除映射,有新的通信时,再重新建⽴共享内存区域。
⽽是保持共享区域,直到通信完毕为⽌,这样,数据内容⼀直保存在共享内存中,并没有写回⽂件。
共享内存中的内容往往是在解除映射时才写回⽂件的。
因此,采⽤共享内存的通信⽅式效率是⾮常⾼的。
⼆、相关函数:与信号量⼀样,在Linux中也提供了⼀组函数接⼝⽤于使⽤共享内存,⽽且使⽤共享共存的接⼝还与信号量的⾮常相似,⽽且⽐使⽤信号量的接⼝来得简单。
它们声明在头⽂件 sys/shm.h中。
1、shmget函数该函数⽤来创建共享内存,它的原型为:int shmget(key_t key, size_t size, int shmflg);1.第⼀个参数,与信号量的semget函数⼀样,程序需要提供⼀个参数key(⾮0整数),它有效地为共享内存段命名。
shmget函数成功时返回⼀个与key相关的共享内存标识符(⾮负整数),⽤于后续的共享内存函数。
调⽤失败返回-1.不相关的进程可以通过该函数的返回值访问同⼀共享内存,它代表程序可能要使⽤的某个资源,程序对所有共享内存的访问都是间接的,程序先通过调⽤shmget函数并提供⼀个键,再由系统⽣成⼀个相应的共享内存标识符(shmget函数的返回值),只有shmget函数才直接使⽤信号量键,所有其他的信号量函数使⽤由semget函数返回的信号量标识符。
如何使用进程间通信在Shell脚本中实现数据共享
如何使用进程间通信在Shell脚本中实现数据共享进程间通信(Inter-process Communication,IPC)是指不同进程之间进行数据交换和共享的机制。
在Shell脚本中,我们可以使用进程间通信来实现数据共享,以便多个进程之间可以互相传递数据并进行协作。
下面将介绍如何使用进程间通信在Shell脚本中实现数据共享。
一、管道(Pipe)管道是一种IPC机制,用于在Shell脚本中将一个进程的输出直接送给另一个进程作为输入。
可以用竖线符号“|”来创建一个管道,将一个命令的输出传递给另一个命令。
下面是一个使用管道在Shell脚本中实现数据共享的例子:```shell#!/bin/bash# 启动进程A并将数据输出到标准输出processA | processB```在这个例子中,进程A的输出会通过管道传递给进程B的标准输入。
这样,进程B就可以读取来自进程A的数据,并进行相应的处理。
二、命名管道(Named Pipe)命名管道是一种特殊的文件,它可以用来实现不同进程之间的通信。
在Shell脚本中,我们可以使用mkfifo命令来创建一个命名管道。
下面是一个使用命名管道在Shell脚本中实现数据共享的例子:```shell#!/bin/bash# 创建一个命名管道mkfifo mypipe# 启动进程A并将数据输出到命名管道processA > mypipe &# 启动进程B并从命名管道读取数据processB < mypipe# 删除命名管道rm mypipe```在这个例子中,进程A将数据输出到命名管道mypipe,而进程B则从命名管道mypipe中读取数据。
这样,进程A和进程B就可以通过命名管道进行数据共享。
三、共享内存(Shared Memory)共享内存是一种进程间通信的方式,它允许不同的进程直接访问同一个内存区域。
在Shell脚本中,我们可以使用shmget、shmat和shmdt等命令来创建和访问共享内存。
C#进程间通信(共享内存)
C#进程间通信(共享内存)进程间通信的⽅式有很多,常⽤的⽅式有:1.共享内存(内存映射⽂件,共享内存DLL)。
2.命名管道和匿名管道。
3.发送消息本⽂是记录共享内存的⽅式进⾏进程间通信,⾸先要建⽴⼀个进程间共享的内存地址,创建好共享内存地址后,⼀个进程向地址中写⼊数据,另外的进程从地址中读取数据。
在数据的读写的过程中要进⾏进程间的同步。
进程间数据同步可以有以下的⽅式1. 互斥量Mutex2. 信号量Semaphore3. 事件Event本⽂中进程间的同步采⽤信号量Semaphore的⽅式同步思想类似于操作系统中⽣产者和消费者问题的处理⽅式。
在A进程中创建共享内存,并开启⼀个线程⽤来读取B进程向共享内存中写⼊的数据,定义两个信号量进⾏读写互斥同步A进程中的程序代码using System;using System.Collections.Generic;using ponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;using System.Runtime.InteropServices;using System.Threading;using System.Diagnostics;namespace AppOne{public partial class AppOneMain : Form{const int INVALID_HANDLE_VALUE = -1;const int PAGE_READWRITE = 0x04;[DllImport("User32.dll")]private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow);[DllImport("User32.dll")]private static extern bool SetForegroundWindow(IntPtr hWnd);//共享内存[DllImport("Kernel32.dll", EntryPoint = "CreateFileMapping")]private static extern IntPtr CreateFileMapping(IntPtr hFile, //HANDLE hFile,UInt32 lpAttributes,//LPSECURITY_ATTRIBUTES lpAttributes, //0UInt32 flProtect,//DWORD flProtectUInt32 dwMaximumSizeHigh,//DWORD dwMaximumSizeHigh,UInt32 dwMaximumSizeLow,//DWORD dwMaximumSizeLow,string lpName//LPCTSTR lpName);[DllImport("Kernel32.dll", EntryPoint = "OpenFileMapping")]private static extern IntPtr OpenFileMapping(UInt32 dwDesiredAccess,//DWORD dwDesiredAccess,int bInheritHandle,//BOOL bInheritHandle,string lpName//LPCTSTR lpName);const int FILE_MAP_ALL_ACCESS = 0x0002;const int FILE_MAP_WRITE = 0x0002;[DllImport("Kernel32.dll", EntryPoint = "MapViewOfFile")]private static extern IntPtr MapViewOfFile(IntPtr hFileMappingObject,//HANDLE hFileMappingObject,UInt32 dwDesiredAccess,//DWORD dwDesiredAccessUInt32 dwFileOffsetHight,//DWORD dwFileOffsetHigh,UInt32 dwFileOffsetLow,//DWORD dwFileOffsetLow,UInt32 dwNumberOfBytesToMap//SIZE_T dwNumberOfBytesToMap);[DllImport("Kernel32.dll", EntryPoint = "UnmapViewOfFile")]private static extern int UnmapViewOfFile(IntPtr lpBaseAddress);[DllImport("Kernel32.dll", EntryPoint = "CloseHandle")]private static extern int CloseHandle(IntPtr hObject);private Semaphore m_Write; //可写的信号private Semaphore m_Read; //可读的信号private IntPtr handle; //⽂件句柄private IntPtr addr; //共享内存地址uint mapLength; //共享内存长//线程⽤来读取数据Thread threadRed;public AppOneMain(){InitializeComponent();init();}///<summary>///初始化共享内存数据创建⼀个共享内存///</summary>privatevoid init(){m_Write = new Semaphore(1, 1, "WriteMap");//开始的时候有⼀个可以写m_Read = new Semaphore(0, 1, "ReadMap");//没有数据可读mapLength = 1024;IntPtr hFile = new IntPtr(INVALID_HANDLE_VALUE);handle = CreateFileMapping(hFile, 0, PAGE_READWRITE, 0, mapLength, "shareMemory"); addr = MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);//handle = OpenFileMapping(0x0002, 0, "shareMemory");//addr = MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);threadRed = new Thread(new ThreadStart(ThreadReceive));threadRed.Start();}///<summary>///线程启动从共享内存中获取数据信息///</summary>private void ThreadReceive(){myDelegate myI = new myDelegate(changeTxt);while (true){try{//m_Write = Semaphore.OpenExisting("WriteMap");//m_Read = Semaphore.OpenExisting("ReadMap");//handle = OpenFileMapping(FILE_MAP_WRITE, 0, "shareMemory");//读取共享内存中的数据://是否有数据写过来m_Read.WaitOne();//IntPtr m_Sender = MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);byte[] byteStr = new byte[100];byteCopy(byteStr, addr);string str = Encoding.Default.GetString(byteStr, 0, byteStr.Length);/////调⽤数据处理⽅法处理读取到的数据m_Write.Release();}catch (WaitHandleCannotBeOpenedException){continue;//Thread.Sleep(0);}}}//不安全的代码在项⽬⽣成的选项中选中允许不安全代码static unsafe void byteCopy(byte[] dst, IntPtr src){fixed (byte* pDst = dst){byte* pdst = pDst;byte* psrc = (byte*)src;while ((*pdst++ = *psrc++) != '\0');}}}}B进程向共享内存中写⼊的数据using System;using System.Collections.Generic;using ponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;using System.Runtime.InteropServices;using System.Threading;namespace AppTwo{public partial class AppTwoMain : Form{const int INVALID_HANDLE_VALUE = -1;const int PAGE_READWRITE = 0x04;//共享内存[DllImport("Kernel32.dll", EntryPoint = "CreateFileMapping")]private static extern IntPtr CreateFileMapping(IntPtr hFile, //HANDLE hFile,UInt32 lpAttributes,//LPSECURITY_ATTRIBUTES lpAttributes, //0UInt32 flProtect,//DWORD flProtectUInt32 dwMaximumSizeHigh,//DWORD dwMaximumSizeHigh,UInt32 dwMaximumSizeLow,//DWORD dwMaximumSizeLow,string lpName//LPCTSTR lpName);[DllImport("Kernel32.dll", EntryPoint = "OpenFileMapping")]private static extern IntPtr OpenFileMapping(UInt32 dwDesiredAccess,//DWORD dwDesiredAccess,int bInheritHandle,//BOOL bInheritHandle,string lpName//LPCTSTR lpName);const int FILE_MAP_ALL_ACCESS = 0x0002;const int FILE_MAP_WRITE = 0x0002;[DllImport("Kernel32.dll", EntryPoint = "MapViewOfFile")]private static extern IntPtr MapViewOfFile(IntPtr hFileMappingObject,//HANDLE hFileMappingObject,UInt32 dwDesiredAccess,//DWORD dwDesiredAccessUInt32 dwFileOffsetHight,//DWORD dwFileOffsetHigh,UInt32 dwFileOffsetLow,//DWORD dwFileOffsetLow,UInt32 dwNumberOfBytesToMap//SIZE_T dwNumberOfBytesToMap);[DllImport("Kernel32.dll", EntryPoint = "UnmapViewOfFile")]private static extern int UnmapViewOfFile(IntPtr lpBaseAddress);[DllImport("Kernel32.dll", EntryPoint = "CloseHandle")]private static extern int CloseHandle(IntPtr hObject);private Semaphore m_Write; //可写的信号private Semaphore m_Read; //可读的信号private IntPtr handle; //⽂件句柄private IntPtr addr; //共享内存地址uint mapLength; //共享内存长Thread threadRed;public AppTwoMain(){InitializeComponent();//threadRed = new Thread(new ThreadStart(init));//threadRed.Start();mapLength = 1024;}private void button1_Click(object sender, EventArgs e){try{m_Write = Semaphore.OpenExisting("WriteMap");m_Read = Semaphore.OpenExisting("ReadMap");handle = OpenFileMapping(FILE_MAP_WRITE, 0, "shareMemory");addr = MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);m_Write.WaitOne();byte[] sendStr = Encoding.Default.GetBytes(textBox1.Text.ToString() + '\0');//如果要是超长的话,应另外处理,最好是分配⾜够的内存if (sendStr.Length < mapLength)Copy(sendStr, addr);m_Read.Release();}catch (WaitHandleCannotBeOpenedException){MessageBox.Show("不存在系统信号量!");return;}}static unsafe void Copy(byte[] byteSrc, IntPtr dst) {fixed (byte* pSrc = byteSrc){byte* pDst = (byte*)dst;byte* psrc = pSrc;for (int i = 0; i < byteSrc.Length; i++){*pDst = *psrc;pDst++;psrc++;}}}}}。
进程间通信之: 共享内存
进程间通信之:共享内存
8.5 共享内存8.5.1 共享内存概述可以说,共享内存是一种最为高效的进程间通信方式。
因为进程可以直接读写内存,不需要任何数据的复制。
为了在多个进程间交换信息,内核专门留出了一块内存区。
这段内存区可以由需要访问的进程将其映射到自己的私有地址空间。
因此,进程就可以直接读写这一内存区而不需要进行数据的复制,从而大大提高了效率。
当然,由于多个进程共享一段内存,因此也需要依靠某种同步机制,如互斥锁和信号量等(请参考本章的共享内存实验)。
其原理示意图如图8.8 所示。
图8.8 共享内存原理示意图
8.5.2 共享内存的应用1.函数说明共享内存的实现分为两个步骤,第一步是创建共享内存,这里用到的函数是shmget(),也就是从内存中获得一段共享内存区域,第二步映射共享内存,也就是把这段创建的共享内存映射到具体的进程空间中,这里使用的函数是shmat()。
到这里,就可以使用这段共享内存了,也就是可以使用不带缓冲的I/O 读写命令对其进行操作。
除此之外,当然还有撤销映射的操作,其函数为shmdt()。
这里就主要介绍这3 个函数。
2.函数格式表8.20 列举了shmget()函数的语法要点。
表8.20 shmget()函数语法要点
所需头文件
#includesys/types.h#includesys/ipc.h#includesys/shm.h
函数原型
intshmget(key_tkey,intsize,intshmflg)。
实验6 进程及进程间的通信之共享内存
实验6 进程及进程间的通信●实验目的:1、理解进程的概念2、掌握进程复制函数fork的用法3、掌握替换进程映像exec函数族4、掌握进程间的通信机制,包括:有名管道、无名管道、信号、共享内存、信号量和消息队列●实验要求:熟练使用该节所介绍fork函数、exec函数族、以及进程间通信的相关函数。
●实验器材:软件:1.安装了Ubunt的vmware虚拟机硬件:PC机一台●实验步骤:1、用进程相关API 函数编程一个程序,使之产生一个进程扇:父进程产生一系列子进程,每个子进程打印自己的PID 然后退出。
要求父进程最后打印PID。
进程扇process_fan.c参考代码如下:2、用进程相关API 函数编写一个程序,使之产生一个进程链:父进程派生一个子进程后,然后打印出自己的PID,然后退出,该子进程继续派生子进程,然后打印PID,然后退出,以此类推。
要求:1) 实现一个父进程要比子进程先打印PID 的版本。
(即打印的PID 一般是递增的)2 )实现一个子进程要比父进程先打印PID 的版本。
(即打印的PID 一般是递减的)进程链1,process_chain1.c的参考代码如下:进程链2,process_chain2.c的参考代码如下:3、编写程序execl.c,实现父进程打印自己的pid号,子进程调用execl函数,用可执行程序file_creat替换本进程。
注意命令行参数。
参考代码如下:/*execl.c*/#include<unistd.h>#include<stdio.h>#include<stdlib.h>int main(int argc,char *argv[]){/*判断入参有没有传入文件名*/if(argc<2){perror("you haven,t input the filename,please try again!\n");exit(EXIT_FAILURE);}pid_t result;result=fork();if(result>0){printf(“I’m parent,my pid:%d, mysun’s pid %d\n”,getpid(), result);}/* 下面代码是调用ls程序,用可执行程序ls替换本进程if(result==0){printf(“I’m sum process my pid is %d\n”,getpid());if(execl("/bin/ls","ls","-l",NULL)<0){perror("execlp error");}}*//*下面程序调用execl函数,用可执行程序file_creat替换本进程*/if(result==0){printf(“I’m sum process my pid is %d\n”,getpid());if(execl("./file_creat","file_creat",argv[1],NULL)<0) perror("execl error!");}其中file_creat.c的代码如下:file_creat.c#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>void create_file(char *filename){/*创建的文件具有可读可写的属性*/if(creat(filename,0666)<0){printf("create file %s failure!\n",filename);exit(EXIT_FAILURE);}else{printf("create file %s success!\n",filename);}}int main(int argc,char *argv[]){/*判断入参有没有传入文件名 */if(argc<2){perror("you haven't input the filename,please try again!\n");exit(EXIT_FAILURE);}create_file(argv[1]);exit(EXIT_SUCCESS);代码分析execl函数会让一个可执行程序运行并替换本进程,那么这个可执行程序就应该有创建一个文件的功能。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
shmkey = ftok( "mcut" , 'a' );
//
计算标识符
//
shmid 开辟共享内存
shmid = shmget( shmkey , sizeof(in_data) , IPC_CREAT | 0666 ) ;
head = pos = shmat( shmid , 0 , 0 ); // 享内存
//
开始写入共享内存
while( *in_ptr != '\0' )
{
*pos = *in_ptr ;
pos++;
in_ptr++;
}
*pos = '\0' ;
shmdt( head );
//
禁止本进程使用这块内存
return 0;
}
#include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <stdio.h>
利用共享内存实现进程间通信
在两个进程间共享数据的方法,至今为止我们只说过利用管道。管道只是利用了输入输出重 定向的原理,非常简单。而且只能在父子进程间使用。很多场合下这种方法是无法满足我们 的要求的。 那么现在,我们又有了一种新的方法——利用共享内存(shared memory)。这可以使我们在 任意两个进程间传递数据,而且也是相对简单容易实现的一个方法。 注意:在正常情况下,一个进程的所使用的内存区是不允许其它进程访问的。这里我们要开 辟的共享内存是例外。 我们来做一个简单的剪贴板。从标准输入向 mcut 输入数据,mcut 将其放在共享内存中,然 后 mpaste 从共享内存中读出数据并显示。
-m
输出有关共享内存(shared memory)的信息
-q
输出有关信息队列(message queue)的信息
-s
输出有关“遮断器”(semaphore)的信息
%ipcs -m
删除 ipc ipcrm -m|-q|-s shm_id %ipcrm -m 105
允许本进程使用这块共
in_ptr = in_data ;
//
开始从标准输入输入数据,暂时存在 in_data 里。
while( (in_tmp=getchar()) != EOF )
{
பைடு நூலகம்
*in_ptr = in_tmp ;
in_ptr++ ;
}
*in_ptr = '\0' ; in_ptr = in_data ;
#include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <stdio.h>
int
main()
{
key_t shmkey;
int
shmid , in_tmp ;
char *head , *pos ,
in_data[4096] , *in_ptr ;
其次,操作共享内存,我们用到了下面的函数 #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h>
int void int
shmget( key_t shmkey , int shmsiz , int flag ); *shmat( int shmid , char *shmaddr , int shmflag ); shmdt( char *shmaddr );
printf( "%s\n" , out_data );
fflush( stdout );
shmdt( head );
//
禁止本进程使用这块共享内存
return 0;
}
如何?明白多少了?
要使用共享内存,应该有如下步骤:
1.开辟一块共享内存
shmget()
2.允许本进程使用共某块共享内存 shmat()
int flag 是这块内存的模式(mode)以及权限标识(关于权限的意思,请参阅本系列第五章)。
模式可取如下值:
新建:IPC_CREAT
使用已开辟的内存:IPC_ALLOC
如果标识符以存在,则返回错误值:IPC_EXCL
然后将“模式” 和“权限标识”进行“或”运算,做为第三个参数。
如: IPC_CREAT | IPC_EXCL | 0666
shmget()是用来开辟/指向一块共享内存的函数。参数定义如下:
key_t shmkey 是这块共享内存的标识符。如果是父子关系的进程间通信的话,这个标识符
用 IPC_PRIVATE 来代替。但是刚才我们的两个进程没有任何关系,所以就用 ftok()算出来
一个标识符使用了。
int shmsiz 是这块内存的大小.
head = pos = shmat( shmid , 0 , 0 ); //
允许本进程使用这块共
out_ptr = out_data ;
//
从共享内存中取得数据
while( *pos != '\0' )
{
*out_ptr = *pos ;
out_ptr++ ;
pos++ ;
}
*out_ptr = '\0' ;
int
main()
{
key_t shmkey;
int
shmid;
char *head , *pos ,
out_data[4096] , *out_ptr ;
享内存
shmkey = ftok( "mcut" , 'a' );
//
计算标识符
//
开辟共享内存
shmid = shmget( shmkey , sizeof(out_data) , IPC_ALLOC | 0666 );
3.写入/读出
4.禁止本进程使用这块共享内存 shmdt()
5.删除这块共享内存
shmctl()或者命令行下 ipcrm
上面的程序中用到了如下函数,我们一一解释一下。
首先是 ftok()。它有两个参数,一个是字符串,一个是字符。字符串一般用当前进程的程 序名,字符一般用来标记这个标识符所标识的共享内存是这个进程所开辟的第几个共享内 存。ftok()会返回一个 key_t 型的值,也就是计算出来的标识符的值。
这个函数成功时返回共享内存的 ID,失败时返回-1。
shmat()是用来允许本进程访问一块共享内存的函数。 int shmid 是那块共享内存的 ID。 char *shmaddr 是共享内存的起始地址 int shmflag 是本进程对该内存的操作模式。如果是 SHM_RDONLY 的话,就是只读模式。其 它的是读写模式 成功时,这个函数返回共享内存的起始地址。失败时返回-1。
中。如果要改变共享内存的状态,用这个结构体指定。
返回值:
成功:0
失败:-1
刚才我们的 mpaste.c 程序中还可以加入这样几句。
struct shmid_ds buf;
... ...
shmctl( shmid , IPC_STAT , &buf );
//
取得共享内存的状态
... ...
shmctl( shmid , IPC_RMID , &buf );
int
shmctl( int shmid , int cmd , struct shmid_ds *buf );
int shmid 是共享内存的 ID。
int cmd 是控制命令,可取值如下:
IPC_STAT
得到共享内存的状态
IPC_SET
改变共享内存的状态
IPC_RMID
删除共享内存
struct shmid_ds *buf 是一个结构体指针。IPC_STAT 的时候,取得的状态放在这个结构体
//
删除共享内存
注意!!!!!!!!!:在使用共享内存,结束程序退出后。如果你没在程序中用 shmctl() 删除共享内存的话,一定要在命令行下用 ipcrm 命令删除这块共享内存。你要是不管的话, 它就一直在那儿放着了。 简单解释一下 ipcs 命令和 ipcrm 命令。
取得 ipc 信息:
ipcs [-m|-q|-s]
shmdt()与 shmat()相反,是用来禁止本进程访问一块共享内存的函数。 参数 char *shmaddr 是那块共享内存的起始地址。 成功时返回 0。失败时返回-1。
此外,还有一个用来控制共享内存的 shmctl()函数如下: #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h>