UNIX 共享内存应用中的问题及解决方法

Linux共享内存常见问题分析 前言 这个是接上篇,本来是记录在一篇草稿上的,但是,内容根本不相关,排版怎么都觉得不好看,也不方便以后查阅。干脆再起一篇。 System V 共享内存问题 shmget创建共享内存问题 shmget函数用来创建一个新的,或者访问一个已存在的共享内存区。 #include #include int shmget(key_t key, size_t size, int 阅读详情
各个 UNIX 平台对 System V 标准的 API 在实现上各有差异,由此对相关共享内存的应用开发方式带来影响,甚至引入难以调试的问题。本文将结合作者在 Tivoli 产品开发中的实际经验,对这些平台相关的问题,以及具有共性的问题,逐一进行分析,并提出解决方法。

简介

共享内存是一种非常重要且常用的进程间通信方式,相对于其它IPC机制,因其速度最快、效率最高,被广泛应用于各类软件产品及应用开发中。System V IPC 为UNIX平台上的共享内存应用制定了统一的API标准,从而为在UNIX/Linux平台上进行跨平台开发提供了极大的便利;开发人员基于一套基本相同的源代码,便可开发出同时支持AIX、Solaris、HP-UX、Linux等平台的产品。

然而,各个平台对System V 标准的API在实现上各有差异,由此对相关应用开发带来影响,甚至引入难以调试的问题。本文将结合作者在Tivoli产品开发中的实际经验,对这些平台相关的问题,以及具有共性的问题,逐一进行分析,并提出解决方法。

 




回页首


1. System V共享内存概述

System V 进程间通信(IPC)包括3种机制:消息队列、信号量、共享内存。消息队列和信号量均是内核空间的系统对象,经由它们的数据需要在内核和用户空间进行额外的数据拷贝;而共享内存和访问它的所有应用程序均同处于用户空间,应用进程可以通过地址映射的方式直接读写内存,从而获得非常高的通信效率。

System V 为共享内存定义了下列API接口函数:

 

# include <sys/types.h>
# include <sys/ipc.h>
# include <sys/shm.h>

key_t	 ftok(const char *pathname, int proj_id);
int	 shmget(key_t key, int size, int shmflg);
void*	 shmat(int shmid, const void *shmaddr, int shmflg);
int	 shmdt(void *shmaddr);
int	 shmctl(int shmid, int cmd, struct shmid_ds *buf);

 

ftok函数用于生成一个键值:key_t key,该键值将作为共享内存对象的唯一性标识符,并提供给为shmget函数作为其输入参数;ftok 函数的输入参数包括一个文件(或目录)路径名:pathname,以及一个额外的数字:proj_id,其中pathname所指定的文件(或目录)要求必须已经存在,且proj_id不可为0;
shmget函数用于创建(或者获取)一个由key键值指定的共享内存对象,返回该对象的系统标识符:shmid;
shmat函数用于建立调用进程与由标识符shmid指定的共享内存对象之间的连接;
shmdt函数用于断开调用进程与共享内存对象之间的连接;
shmctl函数用于对已创建的共享内存对象进行查询、设值、删除等操作;

 




回页首


2. ftok的陷阱

根据pathname指定的文件(或目录)名称,以及proj_id参数指定的数字,ftok函数为IPC对象生成一个唯一性的键值。在实际应用中,很容易产生的一个理解是,在proj_id相同的情况下,只要文件(或目录)名称不变,就可以确保ftok返回始终一致的键值。然而,这个理解并非完全正确,有可能给应用开发埋下很隐晦的陷阱。因为ftok的实现存在这样的风险,即在访问同一共享内存的多个进程先后调用ftok函数的时间段中,如果pathname指定的文件(或目录)被删除且重新创建,则文件系统会赋予这个同名文件(或目录)新的i节点信息,于是这些进程所调用的ftok虽然都能正常返回,但得到的键值却并不能保证相同。由此可能造成的后果是,原本这些进程意图访问一个相同的共享内存对象,然而由于它们各自得到的键值不同,实际上进程指向的共享内存不再一致;如果这些共享内存都得到创建,则在整个应用运行的过程中表面上不会报出任何错误,然而通过一个共享内存对象进行数据传输的目的将无法实现。

AIX、Solaris、HP-UX均明确指出,key文件被删除并重建后,不保证通过ftok得到的键值不变,比如AIX上ftok的man帮助信息即声明:

Attention: If the Path parameter of the ftok subroutine names a file that has been removed while keys still refer to it, the ftok subroutine returns an error. If that file is then re-created, the ftok subroutine will probably return a key different from the original one.

Linux没有提供类似的明确声明,但我们可以通过下面的简单例程test01.c,得到相同的印证:

 

#include <stdio.h>
#include <sys/ipc.h>
void main(int argc, char* argv[])
{
if (argc !=2 ) {
		printf("Usage: %s KeyFile/n e.g. %s /tmp/mykeyfile/n", argv[0], argv[0]);
		return;
	}
	printf("Key generated by ftok:  0x%x/n", ftok(argv[1], 1));
}

 

将上述例程在Red Hat Enterprise Linux AS release 4平台上编程成可执行程序test01,并且通过touch命令在 /tmp目录下创建一个新文件mykeyfile,然后为该文件生成键值:

 

# touch  /tmp/mykeyfile
# ./test01 /tmp/mykeyfile
Key generated by ftok:  0x101000b

 

然后,将/tmp/mykeyfile删除,并且通过vi命令重新创建该文件,再次生成键值:

 

# ./test01 /tmp/mykeyfile
Key generated by ftok:  0x1010017

 

我们可以看到,虽然文件名称都是 /tmp/mykeyfile,并未改变,但由于中间发生了文件删除并重新创建的操作,前后两次所得到的键值已经不再相同。

避免此类问题最根本的方法,就是采取措施保证pathname所指定的文件(或目录)在共享内存的使用期间不被删除,不要使用有可能被删除的文件;或者干脆直接指定键值,而不借助ftok来获取键值。

 




回页首


3. AIX中shmat的问题

AIX系统中,System V各类进程间通信机制在使用中均存在限制。区别于其它UNIX操作系统对IPC机制的资源配置方式,AIX使用了不同的方法;在AIX中定义了 IPC 机制的上限, 且是不可配置的。就共享内存机制而言,在4.2.1及以上版本的AIX系统上,存在下列限制:

  • 对于64位进程,同一进程可连接最多268435456个共享内存段;
  • 对于32位进程,同一进程可连接最多11个共享内存段,除非使用扩展的shmat;

上述限制对于64位应用不会带来麻烦,因为可供连接的数量已经足够大了;但对于32位应用,却很容易带来意外的问题,因为最大的连接数量只有11个。在某些事件触发的多线程应用中,新的线程不断地为进行事件处理而被创建,这些线程如果都需要去连接特定的共享内存,则极有可能造成该进程连接的共享内存数量超过11个,事实上同时拥有几十个甚至上百个处理线程的应用并不少见。一旦超个这个限制值,则所有后续的处理线程都将无法正常工作,从而导致应用运行失败。

下面的例程test02.c演示了这个问题,为了精简代码,它反复连接的是同一个共享内存对象;实际上,无论所连接的共享内存对象是否相同,该限制制约的是连接次数:

 

#include 	<stdio.h>
#include 	<errno.h>	
#include 	<sys/types.h>
#include 	<sys/ipc.h>
#include 	<sys/shm.h>
#define 	MAX_ATTACH_NUM  15

void main(int argc, char* argv[])
{
    key_t       mem_key;
    long        mem_id;
    void*       mem_addr[MAX_ATTACH_NUM];
    int          i;
    if ( ( mem_key = ftok("/tmp/mykeyfile", 1) ) == (key_t)(-1) )  {
            printf("Failed to generate shared memory access key, ERRNO=%d/n",
			errno);
            goto MOD_EXIT;
    }
    if ( ( mem_id = shmget(mem_key, 256, IPC_CREAT) ) == (-1) )  {
            printf("Failed to obtain shared memory ID, ERRNO=%d/n", errno);
            goto MOD_EXIT;
    }
    for ( i=1; i<=MAX_ATTACH_NUM; i++ )  {
		if ( ( mem_addr[i] = (void *)shmat(mem_id, 0, 0) ) == (void *)(-1) )
			printf("Failed to attach shared memory, times [%02d], errno:%d/n", i,
			errno);
		else
			printf("Successfully attached shared memory, times [%02d]/n", i);
    }
MOD_EXIT:
    shmctl(mem_id, IPC_RMID, NULL);
}

 

在AIX系统上,我们将其编译为test02,并运行,可以看到如下输出:

 

Successfully attached shared memory, times [01]	
Successfully attached shared memory, times [02]	
Successfully attached shared memory, times [03]	
Successfully attached shared memory, times [04]	
Successfully attached shared memory, times [05]	
Successfully attached shared memory, times [06]	
Successfully attached shared memory, times [07]	
Successfully attached shared memory, times [08]	
Successfully attached shared memory, times [09]	
Successfully attached shared memory, times [10]	
Successfully attached shared memory, times [11]	
Failed to attach shared memory, times [12], errno:24
Failed to attach shared memory, times [13], errno:24
Failed to attach shared memory, times [14], errno:24
Failed to attach shared memory, times [15], errno:24

 

说明超出11个连接之后,所有后续的共享内存连接都将无法建立。错误码24的定义是EMFILE,AIX给予的解释是:

The number of shared memory segments attached to the calling process exceeds the system-imposed limit。

解决这个问题的方法是,使用扩展的shmat;具体而言就是,在运行相关应用之前(确切地说,是在共享内存被创建之前),首先在shell中设置EXTSHM环境变量,通过它扩展shmat,对于源代码本身无需作任何修改:

 

		export EXTSHM=ON
	

 

值得注意的是,虽然设置环境变量,在程序中也可通过setenv函数来做到,比如在程序的开始,加入下列代码:

 

		setenv("EXTSHM", "ON", 1);
	

 

但实践证明这样的方法在解决这个问题上是无效的;也就是说唯一可行的办法,就是在shell中设置EXTSHM环境变量,而非在程序中。

在AIX上配置32位DB2实例时,也要求确保将环境变量 EXTSHM 设为 ON,这是运行 Warehouse Manager 和 Query Patroller 之前必需的操作:

 

export EXTSHM=ON
db2set DB2ENVLIST=EXTSHM
db2start

 

其原因即来自我们刚刚介绍的AIX中32位应用连接共享内存时,存在最大连接数限制。这个问题同样普遍存在于AIX平台上Oracle等软件产品中。

 




回页首


4. HP-UX中shmget和shmat的问题

4.1 32位和64位应用兼容问题

在HP-UX平台上,如果同时运行32位应用和64位应用,而且它们访问的是一个相同的共享内存区,则会遇到兼容性问题。

在HP-UX中,应用程序设置IPC_CREAT标志调用shmget,所创建的共享内存区,只可被同类型的应用所访问;即32位应用程序所创建的共享内存区只可被其它的32位应用程序访问,同样地,64位应用程序所创建的共享内存区只可被其它的64位应用程序访问。

如果,32位应用企图访问一个由64位应用创建的共享内存区,则会在调用shmget时失败,得到EINVAL错误码,其解释是:

A shared memory identifier exists for key but is in 64-bit address space and the process performing the request has been compiled as a 32-bit executable.

解决这一问题的方法是,当64位应用创建共享内存时,合并IPC_CREAT标志,同时给定IPC_SHARE32标志:

 

shmget(mem_key, size, 0666 | IPC_CREAT | IPC_SHARE32)

 

对于32位应用,没有设定IPC_SHARE32标志的要求,但设置该标志并不会带来任何问题,也就是说无论应用程序将被编译为32位还是64位模式,都可采用如上相同的代码;并且由此解决32位应用和64位应用在共享内存访问上的兼容性问题。

4.2 对同一共享内存的连接数限制

在HP-UX上,应用进程对同一个共享内存区的连接次数被限制为最多1次;区别于上面第3节所介绍的AIX上的连接数限制,HP-UX并未对指向不同共享内存区的连接数设置上限,也就是说,运行在HP-UX上的应用进程可以同时连接很多个不同的共享内存区,但对于同一个共享内存区,最多只允许连接1次;否则,shmat调用将失败,返回错误码EINVAL,在shmat的man帮助中,对该错误码有下列解释:

shmid is not a valid shared memory identifier, (possibly because the shared memory segment was already removed using shmctl(2) with IPC_RMID), or the calling process is already attached to shmid.

这个限制会对多线程应用带来无法避免的问题,只要一个应用进程中有超过1个以上的线程企图连接同一个共享内存区,则都将以失败而告终。

解决这个问题,需要修改应用程序设计,使应用进程具备对同一共享内存的多线程访问能力。相对于前述问题的解决方法,解决这个问题的方法要复杂一些。

作为可供参考的方法之一,以下介绍的逻辑可以很好地解决这个问题:

基本思路是,对于每一个共享内存区,应用进程首次连接上之后,将其键值(ftok的返回值)、系统标识符(shmid,shmget调用的返回值)和访问地址(即shmat调用的返回值)保存下来,以这个进程的全局数组或者链表的形式留下记录。在任何对共享内存的连接操作之前,程序都将先行检索这个记录列表,根据键值和标志符去匹配希望访问的共享内存,如果找到匹配记录,则从记录中直接读取访问地址,而无需再次调用shmat函数,从而解决这一问题;如果没有找到匹配目标,则调用shmat建立连接,并且为新连接上来的共享内存添加一个新记录。

记录条目的数据结构,可定义为如下形式:

 

typedef struct  _Shared_Memory_Record
{
	key_t		mem_key;		// key generated by ftok()			
	int			mem_id;			// id  returned by shmget()			
	void*		mem_addr;		// access address returned by shmat()	
	int			nattach;			// times of attachment				
} Shared_Memory_Record;

 

其中,nattach成员的作用是,记录当前对该共享内存区的连接数目;每一次打开共享内存的操作都将对其进行递增,而每一次关闭共享内存的操作将其递减,直到nattach的数值降到0,则对该共享内存区调用shmdt进行真正的断开连接。

打开共享内存的逻辑流程可参考如下图一:


图一
图一

关闭共享内存的逻辑流程可参考如下图二:


图二
图二




回页首


5. Solaris中的shmdt函数原型问题

Solaris系统中的shmdt调用,在原型上与System V标准有所不同,

 

    Default
     int shmdt(char *shmaddr);
  

 

即形参shmaddr的数据类型在Solaris上是char *,而System V定义的是void * 类型;实际上Solaris上shmdt调用遵循的函数原型规范是SVID-v4之前的标准;以Linux系统为例,libc4和libc5 采用的是char * 类型的形参,而遵循SVID-v4及后续标准的glibc2及其更新版本,均改为采用void * 类型的形参。

如果仍在代码中采用System V的标准原型,就会在Solaris上编译代码时造成编译错误;比如:

 

Error: Formal argument 1 of type char* in call to shmdt(char*) 
is being passed void*.

 

解决方法是,引入一个条件编译宏,在编译平台是Solaris时,采用char * 类型的形参,而对其它平台,均仍采用System V标准的void * 类型形参,比如:

 

		#ifdef  _SOLARIS_SHARED_MEMORY         
	shmdt((char *)mem_addr);	
#else              			
	shmdt((void *)mem_addr);	
#endif
	





回页首


6. 通过shmctl删除共享内存的风险

当进程断开与共享内存区的连接后,一般通过如下代码删除该共享内存:

 

		shmctl(mem_id, IPC_RMID, NULL);	
	

 

从HP-UX上shmctl函数的man帮助,我们可以看到对IPC_RMID操作的说明:

IPC_RMID Remove the shared memory identifier specified by shmid from the system and destroy the shared memory segment and data structure associated with it. If the segment is attached to one or more processes, then the segment key is changed to IPC_PRIVATE and the segment is marked removed. The segment disappears when the last attached process detaches it.

其它UNIX平台也有类似的说明。关于shmctl的IPC_RMID操作,其使用特点可简述如下:

  • 如果共享内存已经与所有访问它的进程断开了连接,则调用IPC_RMID子命令后,系统将立即删除共享内存的标识符,并删除该共享内存区,以及所有相关的数据结构;
  • 如果仍有别的进程与该共享内存保持连接,则调用IPC_RMID子命令后,该共享内存并不会被立即从系统中删除,而是被设置为IPC_PRIVATE状态,并被标记为"已被删除";直到已有连接全部断开,该共享内存才会最终从系统中消失。

    于是,存在这样的一种状态:

    • N个进程(进程1至进程N)已经与某共享内存区连接;
    • 进程1已完成对此共享内存的操作,断开连接后,调用shmctl的IPC_RMID子命令,企图删除该共享内存;
    • 由于进程2至进程N仍保持与该共享内存的连接,因此在它们全部断开连接之前,这个共享内存区毫无疑问地会依然存在。

此时,如果有其它的进程(比如第N+1号进程)想建立对这个共享内存的连接,是否能够成功呢?

类似的状态,在Windows上同样存在,只是程序借助的API有所不同,比如通过CreateFileMapping函数创建共享内存,通过MapViewOfFile函数建立连接,通过UnmapViewOfFile函数断开连接,通过CloseHandle函数删除共享内存等。在Windows上,对此问题的回答是肯定的;也就是说,只要共享内存依然存在,则进程总是可以建立对它的连接,而无论之前是否有进程对其执行过删除操作。

然而,对于包括AIX、Solaris、HP-UX等在内的UNIX平台,答案却是否定的!这也正是本节所讨论的使用shmctl中的风险所在;通过以下test03.P1.c和test03.P2.c两个例程,我们可以很直观地得到答案:

test03.P1.c: 创建共享内存,并建立连接,保持10秒后(在此期间,test03.P2将反复连接、并删除该共享内存),断开连接,并最后再次尝试连接以验证该共享内存是否已被真正删除;

test03.P2.c: 反复连接由test03.P1创建的共享内存,并在期间通过shmctl的IPC_RMID 子命令删除该共享内存,以观察共享内存被执行删除操作之后,在被彻底销毁之前是否还能接受连接;

 

/******* test03.P1.c ********/
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int main(int argc, char* argv[])
{
	key_t       	mem_key;
    long 		mem_id;
    void* 		mem_addr;
	int			isAttached = 0;

    mem_key = ftok("/tmp/mykeyfile", 1);
    mem_id  = shmget(mem_key, 256, IPC_CREAT);

    if ( ( mem_addr = (void *)shmat(mem_id, 0, 0) ) == (void *)(-1) )  
    	printf("%s, Failed to attach shared memory, errno:%d/n", argv[0], errno);
    else { 
    	isAttached = 1;
        printf("%s, +.Successfully attached shared memory/n", argv[0]);
   	}

	/* sleep 10 seconds, to wait test03.P2 to run */ 
	sleep(10);

	if (isAttached) { 
		// Attention: the following line should be "shmdt((char *)mem_addr);" if
		on Solaris 
		shmdt((void *)mem_addr); 
		printf("%s, -.Successfully detached shared memory/n", argv[0]);
	} 

	/* try to attach the shared memory which has been removed! */ 
	if ( ( mem_addr = (void *)shmat(mem_id, 0, 0) ) == (void *)(-1) ) 
		printf("%s, Failed to attach the removed shared memory, errno:%d/n",
		argv[0], errno); 

  	return 0;
}


/******* test03.P2.c ********/
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int main(int argc, char* argv[]) 
{
	key_t 		mem_key; 
   	long   		mem_id; 
    void*   		mem_addr; 
	int			i,  isAttached; 

    mem_key = ftok("/tmp/mykeyfile", 1); 
    mem_id  = shmget(mem_key, 0, 0); 

	// repeated attaching & detaching 
	for (i=1; i<10; i++) { 
		isAttached = 0; 
		if ( ( mem_addr = (void *)shmat(mem_id, 0, 0) ) == (void *)(-1) )
        	printf("%s, Failed to attach shared memory, times [%02d],
			errno:%d/n",
					  argv[0], i, errno); 
	   	else {
       		isAttached = 1;
          	printf("%s, +.Successfully attached shared memory, times
			[%02d]/n",argv[0], i); 
        }

   		if (isAttached) {
      		// Attention: the following line should be "shmdt((char
			*)mem_addr);", if on Solaris
            shmdt((void *)mem_addr); 
       		printf("%s, -.Successfully detached, times [%02d]/n", argv[0], i);
       	}

		// purposely remove the shared memory at times [5]
		if (i==5) { 
			shmctl(mem_id, IPC_RMID, NULL);
			printf("%s, *.Remove executed, times [%02d], errno=%d/n", 
			argv[0], i, errno);
		}
	} 

 	return 0; 
}

 

上述程序均可在AIX、HP-UX、Linux平台上编译通过;在Solaris平台上只需按注释提示的要求,将shmdt的参数强制为char *类型也可编译通过(第5节中已介绍过)。

将test03.P1.c、test03.P2.c各自编译为可执行程序test03.P1、test03.P2,并通过下面的shell脚本:runtest,运行它们:

 

	#!/bin/sh 
	./test03.P1& 
	sleep 2 
	./test03.P2 

 

在Linux平台(Red Hat 8.0)上的运行结果如下:

 

[root@localhost tmp]# ./runtest
./test03.P1, +.Successfully attached shared memory
./test03.P2, +.Successfully attached shared memory, times [01]
./test03.P2, -.Successfully detached, times [01]
./test03.P2, +.Successfully attached shared memory, times [02]
./test03.P2, -.Successfully detached, times [02]
./test03.P2, +.Successfully attached shared memory, times [03]
./test03.P2, -.Successfully detached, times [03]
./test03.P2, +.Successfully attached shared memory, times [04]
./test03.P2, -.Successfully detached, times [04]
./test03.P2, +.Successfully attached shared memory, times [05]
./test03.P2, -.Successfully detached, times [05]
./test03.P2, *.Remove executed, times [05], errno=0
./test03.P2, +.Successfully attached shared memory, times [06]
./test03.P2, -.Successfully detached, times [06]
./test03.P2, +.Successfully attached shared memory, times [07]
./test03.P2, -.Successfully detached, times [07]
./test03.P2, +.Successfully attached shared memory, times [08]
./test03.P2, -.Successfully detached, times [08]
./test03.P2, +.Successfully attached shared memory, times [09]
./test03.P2, -.Successfully detached, times [09]
[root@localhost tmp]# ./test03.P1, -.Successfully detached shared memory
./test03.P1, Failed to attach the removed shared memory, errno:22

 

根据运行结果,我们可以看到,在Linux平台上,即便对共享内存执行了删除操作(在第5次连接之后,test03.P2进程调用了shmctl的IPC_RMID删除操作),只要该共享内存依然存在(test03.P1进程保持着连接,因此共享内存不会被立即删除),则它仍然是可连接的(test03.P2进程的第6到第9次连接均是成功的)。

然而,在AIX、HP-UX、Solaris平台上的运行结果却不同于Linux:

 

# ./runtest
./test03.P1, +.Successfully attached shared memory
./test03.P2, +.Successfully attached shared memory, times [01]
./test03.P2, -.Successfully detached, times [01]
./test03.P2, +.Successfully attached shared memory, times [02]
./test03.P2, -.Successfully detached, times [02]
./test03.P2, +.Successfully attached shared memory, times [03]
./test03.P2, -.Successfully detached, times [03]
./test03.P2, +.Successfully attached shared memory, times [04]
./test03.P2, -.Successfully detached, times [04]
./test03.P2, +.Successfully attached shared memory, times [05]
./test03.P2, -.Successfully detached, times [05]
./test03.P2, *.Remove executed, times [05], errno=0
./test03.P2, Failed to attach shared memory, times [06], errno:22
./test03.P2, Failed to attach shared memory, times [07], errno:22
./test03.P2, Failed to attach shared memory, times [08], errno:22
./test03.P2, Failed to attach shared memory, times [09], errno:22
# ./test03.P1, -.Successfully detached shared memory
./test03.P1, Failed to attach the removed shared memory, errno:22

 

根据结果,可以发现,test03.P2进程的第6到第9次连接都是失败的,也就说明,在AIX、HP-UX、Solaris平台上一旦通过shmctl对共享内存进行了删除操作,则该共享内存将不能再接受任何新的连接,即使它依然存在于系统中!

而且,上面的运行结果,也证明了,对共享内存进行了删除操作之后,当已有的连接全部断开,该共享内存将被系统自动销毁(运行结果的最后一行,说明该共享内存已经不存在了)。

本节的目的在于说明,在AIX、HP-UX、Solaris平台上调用shmctl的IPC_RMID删除操作,是存在潜在风险的,需要足够的谨慎。

如果,可以确知,在删除之后不可能再有新的连接,则执行删除操作是安全的;

否则,在删除操作之后如仍有新的连接发生,则这些连接都将失败!

 




回页首


7. 结论

对共享内存的操作,往往是产品或者应用中数据传输的基础,对其可靠性和性能至关重要;而且作为底层的IPC机制,相关代码具有不易调试的特点,由其造成的问题往往关键却不容易解决。

本文从应用实现的角度上,对在UNIX/Linux平台上使用共享内存可能会遇到的问题,进行了全面的介绍和分析,并给出了解决方法或建议,可供相关的应用开发人员参考。

vscode+keil嵌入式软件开发全流程 阅读详情

相关推荐

图形学基础|球谐光照(Spherical Harmonics Lighting)

球谐光照(Spherical Harmonics Lighting) 文章目录球谐光照(Spherical Harmonics Lighting)一、前言二、球谐函数2.1 基函数2.2 投影与重建2.3 应用三、漫反射环境光3.1 IrradianceMap3.2 数学推导3.3 实践参考博文 一、前言 在学习图形渲染的过程中,一直對球谐函数(球谐光照)有一点了解,但没有亲手实现过。 关于球谐函数的数学概念是比较复杂的,笔者也实在无法完全理解,这篇文章只能从做东西的角度来说,公式是如何和代码进行对应的。

【黑键】 1万+

操作系统——实验2:进程通信(管道及共享内存)

熟悉并掌握管道机制,并实现进程间通信;熟悉并掌握共享内存机制,并实现进程间通信。

阮阮的阮阮的博客 2737

PythonOCC基础使用:建模——倒角倒圆(二维+三维)

占坑

weixin_42755384的博客 4639

共享内存实践总结

经过实验得之,共享内存只有在两个进程同时存在的情况下映射才会成功当共享内存在一个进程映射的情况下,此进程一旦销毁,共享内存即刻销毁,当第二个进程创建共享内存,会有新的共享内存空间。另外console进程,在main函数内部return 0过后进程就OVER了

随心散人专栏 882

(超详细)互补格雷码+相移码求解包裹相位(Python实现)

记录实现“互补格雷码+相移码”求解包裹相位的编码过程。也可以叫它“5+4”法,5代表五幅格雷码图像,4代表四步相移法的四张正弦条纹图。

暴雨梨花博客 3万+

中国银行信息科技岗位笔试

收到笔试只剩四天了,收集的资料,后续会更新

weixin_46050242的博客 4594

操作系统心得-内存管理(持续更新中)

内存管理是操作系统的一大方面,本文总结了笔者在学习相关知识的心得体会。

蒋大钊的博客 1723

基于555定时器的呼吸灯电路

呼吸灯是指LED灯在芯片的控制下完成由亮到暗的逐渐变化,感觉就像人在呼吸,其广泛使用在手机上,起到一个通知提醒的作用。呼吸灯在许多灯光装饰上也有大量使用,如音响、汽车广告牌等,在生活中较为常见。...

qq1074237849的博客 9496

Linux0.11地址映射与共享(HIT OS实验六)

本文讲述了Linux0.11中的内存管理机制,以及HIT操作系统实验6的原理以及实现过程。

weixin_46569289的博客 514

ADS软件操作(10)——DAC控件使用

该控件可以用于为元件定义随频率变换的参数,如放大器的最佳负载阻抗或者源阻抗,需要双频匹配时的优化等,下图是ADS中该控件的模型。

Zhuanzhuyan的博客 4401

解题报告-美团点评2017秋招笔试编程题--常见动态规划问题

晚上就要美团笔试了,在牛客上刷套美团的题练练手,四道题目全都是典型题目,经典的连题面都懒得改那种,也都不难,很基础的动态规划问题。[编程题] 大富翁游戏时间限制:1秒空间限制:32768K大富翁游戏,玩家根据骰子的点数决定走的步数,即骰子点数为1时可以走一步,点数为2时可以走两步,点数为n时可以走n步。求玩家走到第n步(n&lt;=骰子最大点数且是方法的唯一入参)时,总共有多少种投骰子的方法。 输...

聂小白的专栏 1720

转载:UNIX系统共享内存的应用编程技术

UNIX系统共享内存的应用编程技术 中国工商银行惠安县支行(362100) 庄文祥  

gonghc的专栏 1156

【30天从零玩转AI应用开发】第16篇:智能体Agent入门——ReAct框架原理+首个会思考、会动手的AI实战

摘要: 本文介绍了AI智能体(Agent)的核心概念及其与普通大模型(LLM)的区别。通过ReAct(Reason+Act)框架,智能体实现了自主思考、调用工具和分步执行的能力。文章详细讲解了LangChain Agent的四大组件,并推荐新手使用ZERO_SHOT_REACT_DESCRIPTION类型。最后提供了一个完整的智能体实战代码示例,该智能体具备数学计算和天气查询功能,能够自主选择工具完成任务,展示了AI从”被动回答“到”主动行动“的关键进化。

在上海谋生的软件喵记录喵生 626

java共享内存_共享内存在Java中的实现和应用

一起学习郭洪锋 (ghf_emai@china.com)2001 年 9 月1 共享内存对应应用开发的意义对熟知UNIX系统应用开发的程序员来说,IPC(InterProcess Communication)机制是 非常熟悉的,IPC基本包括共享内存、信号灯操作、消息队列、信号处理等部分,是开发应用中非常重要的必不可少的工具。其中共享内存IPC机制的关键,对于数据共享、系统快 速查询、动态配置、减...

weixin_36040903的博客 1737

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

UNIX共享内存总结

    共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式。两个不同进程A、B共享内存的意思是,同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新,反之亦然。由于多个进程共享同一块内存区域,必然需要某种同步机制,互斥锁和信号量都可以。采用共享内存通信的一个显而易见的好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝。因此,采用共

nellson的专栏 1万+

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

unix/linux共享内存应用与陷阱

unix/linux共享内存应用与陷阱   共享内存是系统出于多个进程之间通讯的考虑,而预留的的一块内存区。在/proc/sys/kernel/目录下,记录着共享内存的一些限制,如一个共享内存区的最大字节数shmmax,系统范围内最大共享内存区标识符数shmm

liuyuanqing2010的专栏 631

共享内存 (shared memory)是 Unix下的多进程之间的通信方法

共享内存 (shared memory)是 Unix下的多进程之间的通信方法 ,这种方法通常用于一个程序的多进程间通信,实际上多个程序间也可以通过共享内存来传递信息。本文介绍如何在 Client/Server方式下实现多个程序间共享内存。   问题分析  多个程序之间共享内存 ,首先要解决的问题是怎样让各个程序能够访问同一块内存和相同的信号量。共享内存的 id可以通过调用 shmget(key_t

lijun624的专栏 1810

UNIX下C语言编程与实践53-UNIX 共享内存控制:shmctl 函数与共享内存管理

本文深入解析UNIX共享内存管理核心函数shmctl,详细阐述其三种关键操作:IPC_STAT(属性查询)、IPC_SET(属性修改)和IPC_RMID(资源删除)。通过分析shmid_ds数据结构与共享内存生命周期的关联,结合实例程序展示如何监控和管理共享内存。文章特别强调共享内存管理的重要性,包括避免资源泄漏、确保数据安全和进程同步等关键问题,并提供了常见错误解决方案。最后提出共享内存与信号量协同使用的优化方案,为高效IPC编程提供实践指导。

文石_2009的博客 858

共享内存在java中的实现

共享内存在Java中的实现和应用出自:ibm 郭洪锋 2002年10月15日 23:07共享内存在Java中的实现和应用 内容: 1 共享内存对应应用开发的意义 2 共享内存在java中的实现 3 共享内存在java中的应用 作者介绍 郭洪锋 (ghf_emai@china.com)2001 年 9 月1 共享内存对应应用开发的意义 对熟知UNIX系统应用开发的程序员来

juvencoco的专栏 1889

linux获取共享内存失败2,unix/linux共享内存应用与陷阱

共享内存是系统出于多个进程之间通讯的考虑,而预留的的一块内存区。在/proc/sys/kernel/目录下,记录着共享内存的一些限制,如一个共享内存区的最大字节数shmmax,系统范围内最大共享内存区标识符数shmmni等,可以手工对其调整,但不推荐这样做。一、应用共享内存的使用,主要有以下几个API:ftok()、shmget()、shmat()、shmdt()及shmctl()。1)用ftok...

weixin_33501543的博客 2124

对话UNIX:通过共享内存进行进程间通信

2012-07-20 04:08 335人阅读 评论(0) 收藏 举报 从表面上看,UNIX应用程序单独控制底层主机。它随时可以访问处理器,它的内存是神圣不可侵犯的,连接它的设备只为它服务。但是表面现象会骗人,这样有如君主一般的绝对地位只是幻想而已。UNIX系统同时运行大量应用程序,有限的物理资源要在它们之间共享。处理器能力被划分为时间片,应用程序映像经常被换入和换出真实内存,

T.liu 627
上一篇: Webmin:Unix上的GUI管理工具
下一篇: "operator new" 和"new operator "
inter999
博客等级 码龄19年 18粉丝 9原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值