`

XSI IPC 通信之共享存储

阅读更多
    在XSI IPC通信之消息队列XSI IPC通信之信号量两节中,我们讨论了消息队列和信号量,这一节将继续讨论同属于 XSI IPC 的存储共享。
    共享存储允许多个进程共享一个给定的存储区。因为数据不需要在进程之间复制,所以这是一种较快的 IPC。要注意的是,当一个进程在修改共享存储区时,其他进程不应该去操作这块区域。通常使用信号量来同步共享存储访问(当然也可使用记录锁或互斥量)。
    mmap 就是共享存储的一种形式,它是将同一个文件映射到各个进程的地址空间。XSI 共享存储和内存映射的文件的区别是,前者没有相关的文件。XSI 共享存储段是内存的匿名段。
    下表给出了影响共享存储的系统限制。

    内核为每个共享存储段维护着一个结构,它至少包含下面这些成员。
struct shmid_ds{
    struct ipc_perm  shm_perm;
    size_t           shm_segsz;    // size of segment in bytes
    pid_t            shm_lpid;     // pid of last shmop()
    pid_t            shm_cpid;     // pid of creator
    shmatt_t         shm_nattch;   // number of current attaches
    time_t           shm_atime;    // last-attach time
    time_t           shm_dtime;    // last-detach time
    time_t           shm_ctime;    // last-change time
    /* ... */
};

    其中的 ipc_perm 结构见XSI IPC 相似特征介绍。shmatt_t 类型定义为无符号整型,它至少与 unsigned short 一样大。
    shmget 函数可以创建或获得一个共享存储标识符。shmctl 函数可对共享存储段执行多种操作。shmat 函数可将创建好的共享存储段连接到进程的地址空间中。shmdt 函数可将共享段与进程分离。
#include <sys/shm.h>
int shmget(key_t key, size_t size, int flag);
                        /* 返回值:若成功,返回共享存储 ID;否则,返回 -1 */
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
                        /* 返回值:若成功,返回 0;否则,返回 -1 */
void *shmat(int shmid, const void *addr, int flag);
                  /* 返回值:若成功,返回指向共享存储段的指针;否则,返回 -1 */
int shmdt(const void *addr);
                        /* 返回值:若成功,返回 0;否则,返回 -1 */

    shmget 函数在创建一个新段时,会初始化 shmid_ds 结构的下列成员。
    * ipc_perm 结构按XSI IPC 相似特征介绍一节中的所述进行初始化。该结构中的 mode 按 flag 中的相应权限位设置。
    * shm_lpid、shm_nattach、shm_atime 和 shm_dtime 都设置为 0。
    * shm_ctime 设置为当前时间。
    * shm_segsz 设置为请求的 size。
    参数 size 是共享存储段的长度,以字节为单位,通常将其向上取为系统页长的整数倍。若应用指定的 size 值并非系统页长的整倍数,则最后一页的余下部分是不可使用的。如果是在引用一个现存的段,则可将 size 指定为 0。创建一个新段时,段内的内容会被初始化为 0。
    shmctl 函数的 cmd 参数可指定下列 5 种命令中的一种,使其在 shmid 指定的段上执行。
    * IPC_STAT:取此段的 shmid_ds 结构,并将其存放在 buf 指向的结构中。
    * IPC_SET:将字段 shm_perm.uid、shm_perm.gid、shm_perm.mode 从 buf 指向的结构复制到此队列关联的 shmid_ds 结构中。此命令只能由下列两种进程执行:一种是其有效用户 ID 等于 shm_perm.cuid 或 shm_perm.uid,另一种是具有超级用户特权的进程。
    * IPC_RMID:从系统中删除该共享存储段。因为每个共享存储段维护着一个连接计数(及 shm_nattch字段),所以除非使用该段的最后一个进程终止或与该段分离,否则不会实际上删除该存储段。不过不管此段是否仍在使用,该段标识符都会被立即删除,不能再用 shmat 与该段连接。该命令也只能由上面提及的两种进程执行。
    Linux 和 Solaris 还提供了如下的另外两种命令。
    * SHM_LOCK:在内存中对共享存储段加锁。只能由超级用户执行。
    * SHM_UNLOCK:解锁共享存储段。也只能由超级用户执行。
    共享存储段连接到调用进程的哪个地址上与 shmat 函数的 addr 参数以及 flag 中是否指定了 SHM_RND 位有关,有以下几种情况。
    (1)如果 addr 为 0,则此段连接到由内核选择的第一个可用地址上(推荐)。
    (2)如果 addr 非 0,并且没有指定 SHM_RND,则此段连接到 addr 所指定的地址上。
    (3)如果 addr 非 0,并且指定了 SHM_RND,则此段连接到(addr - (addr mod SHMLBA))所表示的地址上。SHM_RND 命令的意思是“取整”,SHMLBA 的意思是“低边界地址倍数”,它总是 2 的乘方,该算式是将地址向下取最近 1 个 SHMLBA 的倍数。
    如果在 flag 中指定了 SHM_RDONLY 位,则以只读方式连接此段,否则以读写方式连接。
    shmat 的返回值是该段所连接的实际地址,如果出错则返回 -1。如果 shmat 成功执行,那么内核将使相应 shmid_ds 结构中的 shm_nattch 计数器值加一。
    当对共享存储段的操作已经结束时,就可调用 shmdt 函数与该段分离。不过这并不从系统中删除其标识符以及相关的数据结构,该标识符仍然存在,直至某个进程调用带 IPC_RMID 命令的 shmctl 函数来特地删除它为止。其中的 addr 参数是之前调用 shmat 时的返回值。如果成功,shmdt 将使相关 shmid_ds 结构中的 shm_nattch 计数器减一。
    下面这个实例演示了将 addr 参数设为 0 的 shmat 函数的用法,它打印了一些特定系统存放各种类型的数据的位置信息(这些信息的说明见C 存储及环境一节)。
#include <stdio.h>
#include <stdlib.h>
#include <sys/shm.h>

#define ARRAY_SIZE	40000
#define MALLOC_SIZE	100000
#define SHM_SIZE	100000
#define SHM_MODE	0600	// user read/write

char array[ARRAY_SIZE];		// uninitialized data = bss

int main(void){
	int	shmid;
	char *ptr, *shmptr;

	printf("array[] from %p to %p\n", &array[0], &array[ARRAY_SIZE]);
	printf("stack around %p\n", &shmid);

	if((ptr=malloc(MALLOC_SIZE)) == NULL){
		printf("malloc error\n");
		exit(1);
	}
	printf("malloced from %p to %p\n", ptr, ptr+MALLOC_SIZE);

	shmid = shmget(IPC_PRIVATE, SHM_SIZE, SHM_MODE);
	if((shmptr=shmat(shmid, 0, 0)) != (void *)-1){
		printf("shared memory attached from %p to %p\n", shmptr, shmptr+SHM_SIZE);
		shmctl(shmid, IPC_RMID, 0);
	}
	exit(0);
}

    在一个基于 Intel 的 64 位 Linux 系统上运行此程序的结果如下:
$ ./prtMemoryLayout.out
array[] from 0x6020c0 to 0x60bd00
stack around 0x7fff957b146c
malloced from 0x9e3010 to 0x9fb6b0
shared memory attached from 0x7fba578ab000 to 0x7fba578c36a0

    下图显示了这种存储区布局示意图。

  • 大小: 7.5 KB
  • 大小: 8.9 KB
分享到:
评论

相关推荐

    linux 中 xsi ipc的简单使用

    Linux中的XSI IPC(System V Interprocess Communication)是系统V接口的一种实现,它提供了一种在不同进程间共享数据的方法。XSI IPC包括了三种主要机制:消息队列、信号量和共享内存。这些机制允许进程之间进行...

    利用semaphore实现shm进程通信

    其中,信号量结合共享存储区(ShareMemory)和消息传递统称为XSI IPC(扩展系统接口进程间通信),提供了一种高效的进程间通信机制。 #### 共享存储与信号量:一种高效IPC方案 文章进一步探讨了信号量与共享存储区...

    liferay ipc porltet间通信DEMO

    Liferay IPC机制使得不同的portlet能够共享数据和事件,增强了portlet之间的协作能力。这种通信方式分为两种主要类型:异步(Asynchronous)和同步(Synchronous)。异步通信通常用于不阻塞用户界面的背景任务,而...

    XSI融和球插件

    【XSI融和球插件】是一款专为Softimage XSI(现在称为SILVERGUN)设计的强大特效工具,其在3D动画和视觉效果领域具有广泛的应用。这款插件以其独特的“融合球”技术著称,允许艺术家创建出高度复杂的形状和动态效果...

    XSI的植物生成插件

    T-Gen是第一个完全整合进XSI的植物生成插件。超过100种造型和分布的参数,与XSI的曲线和基于节点的体系完美配合确保了用户创造自定性的植物时拥有强大的灵活性和无穷的可能性。你可以使用几乎所有的XSI工具对T-Gen...

    XSI经典插件emFluid3破解版

    XSI经典插件emFluid3破解版XSI经典插件emFluid3破解版XSI经典插件emFluid3破解版XSI经典插件emFluid3破解版

    xml中的xmlns:、xmlns:xsi和xsi:schemaLocation.doc

    "XML中的xmlns、xmlns:xsi和xsi:schemaLocation详解" XML文档中的xmlns、xmlns:xsi和xsi:schemaLocation是三个重要的元素,分别用于定义XML文档的命名空间、XML schema实例和schemaLocation。 一、xmlns xmlns是...

    xsi_python

    字符串是 Python 中最基本的数据类型之一,用于存储文本信息。在 XSI 脚本中,字符串常用来处理文件路径、对象名称等。 **2.2.2 数字** Python 支持多种数字类型,包括整数、浮点数和复数等。这些数据类型在处理...

    SPH.rar_SPH_SPH XSI_xsi sph plugin

    标题中的"SPH.rar_SPH_SPH XSI_xsi sph plugin"揭示了这是一个与流体模拟相关的软件插件,主要用于3D建模和动画软件Softimage XSI(也称为XSI)。SPH代表Smoothed Particle Hydrodynamics(平滑粒子流体动力学),这...

    softimage xsi keygen

    Autodesk SoftImage 2013 的破解工具。 你懂的

    XSI 2011 keygen downloader

    keygen downloader for xsi 2011 x 64. The way to finder keygen

    XSI 7 的破解方法

    XSI 7 的破解方法,图片视图,很直观,请多多支持,谢谢!!!

    XSI2012 注册机

    Softimage|XSI2012注册机 x32 x64 艺术挑战技术,技术启发艺术

    linux-ipcs:Linux进程间通信(Inter-Process Communication)方式汇总

    另外普通的mutex是作用线程间同步用的,但是可以将进程A和进程B共享的内存中初始化一个mutex,这样就可以用将此mutex用作进程间通信用了。 扩展 进程与内核通信 其实本来的计划是分两个大块,一块写进程间通信,一块...

    五大短距无线通信技术比较

    UWB技术的标准制定过程中出现了Intel与TI为代表的MBOA提案和以摩托罗拉与XSI为代表的DS-CDMA提案两大阵营。虽然无线电制造商PulseLink提出了一种允许不同UWB系统共存的公共信号协议(CSP),但仍面临标准统一的问题...

    Springboot实现多服务器session共享

    2. 配置Redis服务器,用于存储Session数据。 3. 在应用程序中使用Spring Session代替传统的HTTPSession。 4. 使用Nginx或其他反向代理服务器来管理多个实例,并将请求分发到不同的实例上。 结论 Springboot实现...

    c#设置xml内容不换行及属性xsi:nil=true的空节点添加

    为了创建这样一个空节点,可以使用`XmlDocument`类创建一个新元素,并添加`xsi:nil`属性设置为`"true"`。代码示例如下: ```csharp public static XmlElement CreateNodeWithNullAttr(XmlDocument doc, string ...

Global site tag (gtag.js) - Google Analytics