<轉>UNIX 共享內存應用中的問題及解決方法

http://www.ibm.com/developerworks/cn/aix/library/au-cn-sharemem/shell

 

共享內存是一種很是重要且經常使用的進程間通訊方式,相對於其它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接口函數:app

 

# 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.P一、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平臺上使用共享內存可能會遇到的問題,進行了全面的介紹和分析,並給出瞭解決方法或建議,可供相關的應用開發人員參考。

 

參考資料

關於做者

劉新華,IBM 中國軟件開發中心軟件工程師。參與過 IBM Rational、Tivoli 等產品開發,最近從事 IBM Tivoli OMEGAMON XE for Message Transaction Tracking 的產品開發工做,對 Linux 內核技術、以及實時和嵌入式應用也有濃厚的興趣。

相關文章
相關標籤/搜索