进程通信之共享内存「建议收藏」

进程通信之共享内存

大家好,又见面了,我是全栈君。

共享内存
共享内存就是同意两个不相关的进程訪问同一个逻辑内存。共享内存是在两个正在执行的进程之间共享和传递数据的一种很有效的方式。不同进程之间共享的内存通常安排为同一段物理内存。

进程能够将同一段共享内存连接到它们自己的地址空间中,全部进程都能够訪问共享内存中的地址。就好像它们是由用C语言函数malloc分配的内存一样。

而假设某个进程向共享内存写入数据,所做的修改将马上影响到能够訪问同一段共享内存的不论什么其它进程。

共享内存并未提供同步机制,也就是说。在第一个进程结束对共享内存的写操作之前,并无自己主动机制能够阻止第二个进程開始对它进行读取。

所以我们通常须要用其它的机制来同步对共享内存的訪问。

http://blog.csdn.net/xiaoliangsky/article/details/40024657

共享内存相关的函数

1创建共享内存shmget

函数原型:int   shmget(key_t   key,   size_t   size,   int  shmflag);

key: 标识符的规则
size:共享存储段的字节数
shmflag:读写的权限
返回值:成功返回共享存储的id,失败返回-1
———————————————–
key 标识共享内存的键值:0/IPC_PRIVATE。当key的取值为IPC_PRIVATE创建一块新的内存;假设key的取值为0。而參数shmflg中设置了IPC_PRIVATE这个标志,则相同将创建一块新的共享内存。

在IPC的通信模式下,无论是使用消息队列还是共享内存。甚至是信号量,每一个IPC的对象(object)都有唯一的名字。称为“键”(key)。

通过“键”。进程可以识别所用的对象。“键”与IPC对象的关系就如同文件名称称之于文件,通过文件名称。进程可以读写文件内的数据,甚至多个进程可以共用一个文件。而在IPC的通讯模式下。通过“键”的使用也使得一个IPC对象能为多个进程所共用。
Linux系统中的全部表示System V中IPC对象的数据结构都包括一个ipc_perm结构。当中包括有IPC对象的键值。该键用于查找System V中IPC对象的引用标识符。

假设不使用“键”,进程将无法存取IPC对象,由于IPC对象并不存在于进程本身使用的内存中。

通常,都希望自己的程序能和其它的程序预先约定一个唯一的键值,但实际上并非总可能的成行的。由于自己的程序无法为一块共享内存选择一个键值。因此,在此把key设为IPC_PRIVATE。这样。操作系统将忽略键,建立一个新的共享内存,指定一个键值。然后返回这块共享内存IPC标识符ID。

而将这个新的共享内存的标识符ID告诉其它进程能够在建立共享内存后通过派生子进程,或写入文件或管道来实现。

int size(单位字节Byte)
———————————————–
    size是要建立共享内存的长度。全部的内存分配操作都是以页为单位的。所以假设一段进程仅仅申请一块仅仅有一个字节的内存,内存也会分配整整一页(在i386机器中一页的缺省大小PACE_SIZE=4096字节)这样,新创建的共享内存的大小实际上是从size这个參数调整而来的页面大小。即假设size为1至4096,则实际申请到的共享内存大小为4K(一页);4097到8192,则实际申请到的共享内存大小为8K(两页),依此类推。

int shmflg
———————————————–
    shmflg主要和一些标志有关。

当中有效的包含IPC_CREAT和IPC_EXCL,它们的功能与open()的O_CREAT和O_EXCL相当。
    IPC_CREAT   假设共享内存不存在,则创建一个共享内存,否则打开操作。
    IPC_EXCL    仅仅有在共享内存不存在的时候,新的共享内存才建立,否则就产生错误。

    假设单独使用IPC_CREAT,shmget()函数要么返回一个已经存在的共享内存的操作符,要么返回一个新建的共享内存的标识符。假设将IPC_CREAT和IPC_EXCL标志一起使用,shmget()将返回一个新建的共享内存的标识符。假设该共享内存已存在,或者返回-1。IPC_EXEL标志本身并没有太大的意义,可是和IPC_CREAT标志一起使用能够用来保证所得的对象是新建的。而不是打开已有的对象。对于用户的读取和写入许可指定SHM_R和SHM_W,(SHM_R>3)和(SHM_W>3)是一组读取和写入许可。而(SHM_R>6)和(SHM_W>6)是全局读取和写入许可。

返回值
———————————————–
成功返回共享内存的标识符。不成功返回-1,errno储存错误原因。
    EINVAL        參数size小于SHMMIN或大于SHMMAX。

    EEXIST        预建立key所致的共享内存,但已经存在。
    EIDRM         參数key所致的共享内存已经删除。
    ENOSPC        超过了系统同意建立的共享内存的最大值(SHMALL )。
    ENOENT        參数key所指的共享内存不存在,參数shmflg也未设IPC_CREAT位。
    EACCES        没有权限。

    ENOMEM        核心内存不足。


2 连接共享内存shmat

函数原型:void* shmat(int shmid, const void *shmaddr, int shmflag)

连接共享内存标识符为shmid的共享内存,连接成功后把共享内存区对象映射到调用
进程的地址空间。随后能够像在本地空间一样訪问。

———————————————–

shmid 共享内存标识符。由shmget函数返回的id
shmaddr 指点共享内存出如今进程内存地址的什么位置,直接指定为NULL时。有内核自己决定
一个合适的地址位置。
shmflg SHM_RDONLY:为仅仅读模式,其它为读写模式

返回值

———————————————–

成功:附件好的共享内存地址
出错:-1。错误原因存在于error中
注意:fork后子进程继承已连接的共享内存地址。

exec后该子进程与共享的内存地址自己主动脱离。
进程结束后。已连接的共享内存地址会自己主动脱离。

错误代码

———————————————–

EACCES:无权限已指定方式连接共享内存
EINVAL:    无效的參数shmid或shmaddr
ENOEME:核心内存不足


3“分离”共享内存shmdt

函数原型:int shmdt(const void *shmaddr)

用来断开与共享内存附加点的地址空间。阻止本进程訪问此片共享内存。

shmaddr:连接的共享内存的起始地址

返回值

———————————————–

成功返回0
出错返回-1。错误原因存在于error中
注意:本函数调用并不删除所指定的共享内存区。而仅仅是将先前用shmat函数连接(attach)好的共享内存脱离(detach)眼下的进程

错误码

———————————————–

EINVAL:无效的參数shmaddr

4管理共享内存shmctl

函数原型:int  shmctl(int   shmid,    int   cmd,    struct   shmid_ds   *buf)

管理共享没存。

———————————————–

shmid 共享内存标识符
cmd     IPC_STAT:得到共享内存的状态,把共享内存的shmid_ds结构拷贝到buf;
            IPC_SET:改变共享内存的状态,把shmid_ds中的uid、gid、mode拷贝到共享内存的shmid_ds结构体。
            IPC_RMID:删除这片共享内存
buf 共享内存管理结构体。详细说明參见贡献内存内核结构定义部分。

返回值

———————————————–

成功返回0
出错返回-1,错误原因存在于error中

错误代码

———————————————–

EACCESS:參数cmd为IPC_STAT,确无权限读取该共享内存
EFAULT:參数buf指向无效的内存地址
EIDRM:标识符为msqid的共享内存已被删除

EINVAL:无效的參数cmd或shmid
EPERM:參数cmd为IPC_SET或IPC_RMID,却无足够的权限运行

最后来一个样例:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/wait.h>
#include <error.h>

#define MEMORY_SIZE 1024

int main()
{
	int               wpid;
	int               status;
	int               failed;
	int               shmid;
	char             *addr;
	pid_t             pid;
	struct shmid_ds   buf;

	failed = 0;

	shmid  = shmget(IPC_PRIVATE, MEMORY_SIZE, IPC_CREAT|0600);
	if (shmid == -1)
	{
		perror("shmget error");
		return -1;
	}

	pid = fork();
	if (pid == 0)
	{
		addr = (char*)shmat(shmid, NULL, 0);
		if ((int)addr == -1)
		{
			perror("shmat addr error");
			return -1;
		}

		strcpy(addr, "I am the child process\n");

		shmdt(addr);
		
		return 3;
	}
	else if (pid > 0)
	{
		wpid = waitpid(pid, &status, 0);
		if (wpid > 0 && WIFEXITED(status))
		{
			printf("child process return is %d\n", WEXITSTATUS(status));
		}

		failed = shmctl(shmid, IPC_STAT, &buf);
		if (failed == -1)
		{
			perror("chmctl error");
			return -1;
		}
		
		printf("shm_segsz =%d bytes\n", buf.shm_segsz);
        printf("parent pid=%d, shm_cpid = %d \n", getpid(), buf.shm_cpid);
        printf("chlid pid=%d, shm_lpid = %d \n", pid, buf.shm_lpid);
		printf("mode = %08x \n", buf.shm_perm.mode);

		addr = (char*)shmat(shmid, NULL, 0);
		if ((int)addr == -1)
		{
			perror("shmat addr error");
			return -1;
		}
	
		printf("%s", addr);
		shmdt(addr);
		shmctl(shmid, IPC_RMID, NULL);
	}	
	else 
	{
		perror("fork error");
		shmctl(shmid, IPC_RMID, NULL);
		return -1;
	}

	return 0;
}

未完

待续;

參考:

http://blog.csdn.net/guoping16/article/details/6584058


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/115812.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • C语言qsort函数用法

    C语言qsort函数用法qsort函数简介   排序方法有很多种:选择排序,冒泡排序,归并排序,快速排序等。看名字都知道快速排序是目前公认的一种比较好的排序算法。因为他速度很快,所以系统也在库里实现这个算法,便于我们的使用。这就是qsort函数(全称quicksort)。它是ANSIC标准中提供的,其声明在stdlib.h文件中,是根据二分法写的,其时间复杂度为n*log(n)  功能:

  • ctk框架搭建(一) ctk框架插件加载与项目结构

    ctk框架搭建(一) ctk框架插件加载与项目结构序 使用CTK框架开发有大半年了,就实际应用上来说框架还比较可靠,但网上资料很少。而刚接触时项目已经有了相当大的体量,与业务等其他逻辑混淆,现在单独把ctk框架部分抽离出来做个总结分享,避免后来的人走弯路。 该系列介绍简单的ctk框架构建的方法,具体架构可根据自身项目设计,开发环境为macOSHighSierra,QtCreator5.10.0。ctk框架插件    CTK源码可以从Gi…

  • winform与cefsharp混合开发_winform窗体

    winform与cefsharp混合开发_winform窗体CefSharpGitHub地址:传送门wiki帮助文档地址:传送门简介CefSharp简单来说就是一款基于.Net写的,支持在Winform和WPF中内嵌的Chrome浏览器的第三方包。快速入门安装要求:VisualStudiowithNuGetPackageManager(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt;=2010).使用Nuget添加引用,搜索CefSharp,

  • 五分钟了解Mysql的行级锁——《深究Mysql锁》「建议收藏」

    五分钟了解Mysql的行级锁——《深究Mysql锁》「建议收藏」我们首先需要知道的一个大前提是:mysql的锁是由具体的存储引擎实现的。所以像MyISAM和InnoDB引擎的锁实现机制是有区别的。Mysql有三种级别的锁定:表级锁定、页级锁定、行级锁定表级锁定参考:三分钟了解Mysql的表级锁——《深究Mysql》页级锁定参考:[三分钟了解Mysql的页级锁——《深究Mysql》]一、定义每次锁定的是一行数据的锁机制就是行级别锁定(r…

  • fiddler抓包模拟器教程_wpe手机模拟器抓包

    fiddler抓包模拟器教程_wpe手机模拟器抓包1.打开,Fiddler.点击tools设置,把HPPPS证书保存在桌面,拖动到安卓模拟器里面.重启Fiddler2.长按网络,修改主机名和端口.在设置[安全]里,添加证书.转载于:https://www.cnblogs.com/limi2019/articles/11411904.html…

  • 使用WiX Toolset创建.NET程序发布Bootstrapper(安装策略管理)(二)——自定义安装

    使用WiX Toolset创建.NET程序发布Bootstrapper(安装策略管理)(二)——自定义安装自定义产品卸载方式        继续从上一次的基础上前进,现在我们已经知道了最简单的bootstrapper打包方法,现在我们对其中的每个节点深入自定义,争取可以达到我们需要的效果。先把最后全部的XML贴出来。

    2022年7月20日

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号