亚洲精品久久久中文字幕-亚洲精品久久片久久-亚洲精品久久青草-亚洲精品久久婷婷爱久久婷婷-亚洲精品久久午夜香蕉

您的位置:首頁技術(shù)文章
文章詳情頁

UNIX 共享內(nèi)存應(yīng)用中的問題及解決方法

瀏覽:4日期:2024-06-14 08:04:26

簡介

共享內(nèi)存是一種非常重要且常用的進程間通信方式,相對于其它IPC機制,因其速度最快、效率最高,被廣泛應(yīng)用于各類軟件產(chǎn)品及應(yīng)用開發(fā)中。System V IPC 為Unix平臺上的共享內(nèi)存應(yīng)用制定了統(tǒng)一的API標準,從而為在UNIX/Linux平臺上進行跨平臺開發(fā)提供了極大的便利;開發(fā)人員基于一套基本相同的源代碼,便可開發(fā)出同時支持AIX、Solaris、HP-UX、Linux等平臺的產(chǎn)品。

然而,各個平臺對System V 標準的API在實現(xiàn)上各有差異,由此對相關(guān)應(yīng)用開發(fā)帶來影響,甚至引入難以調(diào)試的問題。本文將結(jié)合作者在Tivoli產(chǎn)品開發(fā)中的實際經(jīng)驗,對這些平臺相關(guān)的問題,以及具有共性的問題,逐一進行分析,并提出解決方法。

1. System V共享內(nèi)存概述

System V 進程間通信(IPC)包括3種機制:消息隊列、信號量、共享內(nèi)存。消息隊列和信號量均是內(nèi)核空間的系統(tǒng)對象,經(jīng)由它們的數(shù)據(jù)需要在內(nèi)核和用戶空間進行額外的數(shù)據(jù)拷貝;而共享內(nèi)存和訪問它的所有應(yīng)用程序均同處于用戶空間,應(yīng)用進程可以通過地址映射的方式直接讀寫內(nèi)存,從而獲得非常高的通信效率。

System V 為共享內(nèi)存定義了下列API接口函數(shù):

# 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函數(shù)用于生成一個鍵值:key_t key,該鍵值將作為共享內(nèi)存對象的唯一性標識符,并提供給為shmget函數(shù)作為其輸入?yún)?shù);ftok 函數(shù)的輸入?yún)?shù)包括一個文件(或目錄)路徑名:pathname,以及一個額外的數(shù)字:proj_id,其中pathname所指定的文件(或目錄)要求必須已經(jīng)存在,且proj_id不可為0;shmget函數(shù)用于創(chuàng)建(或者獲取)一個由key鍵值指定的共享內(nèi)存對象,返回該對象的系統(tǒng)標識符:shmid;shmat函數(shù)用于建立調(diào)用進程與由標識符shmid指定的共享內(nèi)存對象之間的連接;shmdt函數(shù)用于斷開調(diào)用進程與共享內(nèi)存對象之間的連接;shmctl函數(shù)用于對已創(chuàng)建的共享內(nèi)存對象進行查詢、設(shè)值、刪除等操作;

2. ftok的陷阱

根據(jù)pathname指定的文件(或目錄)名稱,以及proj_id參數(shù)指定的數(shù)字,ftok函數(shù)為IPC對象生成一個唯一性的鍵值。在實際應(yīng)用中,很容易產(chǎn)生的一個理解是,在proj_id相同的情況下,只要文件(或目錄)名稱不變,就可以確保ftok返回始終一致的鍵值。然而,這個理解并非完全正確,有可能給應(yīng)用開發(fā)埋下很隱晦的陷阱。因為ftok的實現(xiàn)存在這樣的風險,即在訪問同一共享內(nèi)存的多個進程先后調(diào)用ftok函數(shù)的時間段中,如果pathname指定的文件(或目錄)被刪除且重新創(chuàng)建,則文件系統(tǒng)會賦予這個同名文件(或目錄)新的i節(jié)點信息,于是這些進程所調(diào)用的ftok雖然都能正常返回,但得到的鍵值卻并不能保證相同。由此可能造成的后果是,原本這些進程意圖訪問一個相同的共享內(nèi)存對象,然而由于它們各自得到的鍵值不同,實際上進程指向的共享內(nèi)存不再一致;如果這些共享內(nèi)存都得到創(chuàng)建,則在整個應(yīng)用運行的過程中表面上不會報出任何錯誤,然而通過一個共享內(nèi)存對象進行數(shù)據(jù)傳輸?shù)哪康膶o法實現(xiàn)。

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 KeyFilen e.g. %s /tmp/mykeyfilen", argv[0], argv[0]);return;}printf("Key generated by ftok: 0x%xn", ftok(argv[1], 1));}

將上述例程在Red Hat Enterprise Linux AS release 4平臺上編程成可執(zhí)行程序test01,并且通過touch命令在 /tmp目錄下創(chuàng)建一個新文件mykeyfile,然后為該文件生成鍵值:

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

然后,將/tmp/mykeyfile刪除,并且通過vi命令重新創(chuàng)建該文件,再次生成鍵值:

# ./test01 /tmp/mykeyfileKey generated by ftok: 0x1010017

我們可以看到,雖然文件名稱都是 /tmp/mykeyfile,并未改變,但由于中間發(fā)生了文件刪除并重新創(chuàng)建的操作,前后兩次所得到的鍵值已經(jīng)不再相同。

避免此類問題最根本的方法,就是采取措施保證pathname所指定的文件(或目錄)在共享內(nèi)存的使用期間不被刪除,不要使用有可能被刪除的文件;或者干脆直接指定鍵值,而不借助ftok來獲取鍵值。

3. AIX中shmat的問題

AIX系統(tǒng)中,System V各類進程間通信機制在使用中均存在限制。區(qū)別于其它UNIX操作系統(tǒng)對IPC機制的資源配置方式,AIX使用了不同的方法;在AIX中定義了 IPC 機制的上限, 且是不可配置的。就共享內(nèi)存機制而言,在4.2.1及以上版本的AIX系統(tǒng)上,存在下列限制:

對于64位進程,同一進程可連接最多268435456個共享內(nèi)存段;

對于32位進程,同一進程可連接最多11個共享內(nèi)存段,除非使用擴展的shmat;

上述限制對于64位應(yīng)用不會帶來麻煩,因為可供連接的數(shù)量已經(jīng)足夠大了;但對于32位應(yīng)用,卻很容易帶來意外的問題,因為最大的連接數(shù)量只有11個。在某些事件觸發(fā)的多線程應(yīng)用中,新的線程不斷地為進行事件處理而被創(chuàng)建,這些線程如果都需要去連接特定的共享內(nèi)存,則極有可能造成該進程連接的共享內(nèi)存數(shù)量超過11個,事實上同時擁有幾十個甚至上百個處理線程的應(yīng)用并不少見。一旦超個這個限制值,則所有后續(xù)的處理線程都將無法正常工作,從而導(dǎo)致應(yīng)用運行失敗。

下面的例程test02.c演示了這個問題,為了精簡代碼,它反復(fù)連接的是同一個共享內(nèi)存對象;實際上,無論所連接的共享內(nèi)存對象是否相同,該限制制約的是連接次數(shù):

#include <stdio.h>#include <errno.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>#define MAX_ATTACH_NUM 15void main(int argc, char* argv[]){key_t  mem_key;longmem_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=%dn",errno);goto MOD_EXIT;}if ( ( mem_id = shmget(mem_key, 256, IPC_CREAT) ) == (-1) ) {printf("Failed to obtain shared memory ID, ERRNO=%dn", 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:%dn", i,errno);elseprintf("Successfully attached shared memory, times [%02d]n", i);}MOD_EXIT:shmctl(mem_id, IPC_RMID, NULL);}

在AIX系統(tǒng)上,我們將其編譯為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:24Failed to attach shared memory, times [13], errno:24Failed to attach shared memory, times [14], errno:24Failed to attach shared memory, times [15], errno:24

說明超出11個連接之后,所有后續(xù)的共享內(nèi)存連接都將無法建立。錯誤碼24的定義是EMFILE,AIX給予的解釋是:

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

解決這個問題的方法是,使用擴展的shmat;具體而言就是,在運行相關(guān)應(yīng)用之前(確切地說,是在共享內(nèi)存被創(chuàng)建之前),首先在shell中設(shè)置EXTSHM環(huán)境變量,通過它擴展shmat,對于源代碼本身無需作任何修改:

export EXTSHM=ON

值得注意的是,雖然設(shè)置環(huán)境變量,在程序中也可通過setenv函數(shù)來做到,比如在程序的開始,加入下列代碼:

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

但實踐證明這樣的方法在解決這個問題上是無效的;也就是說唯一可行的辦法,就是在shell中設(shè)置EXTSHM環(huán)境變量,而非在程序中。

在AIX上配置32位DB2實例時,也要求確保將環(huán)境變量 EXTSHM 設(shè)為 ON,這是運行 Warehouse Manager 和 Query Patroller 之前必需的操作:

export EXTSHM=ONdb2set DB2ENVLIST=EXTSHMdb2start

其原因即來自我們剛剛介紹的AIX中32位應(yīng)用連接共享內(nèi)存時,存在最大連接數(shù)限制。這個問題同樣普遍存在于AIX平臺上Oracle等軟件產(chǎn)品中。

4. HP-UX中shmget和shmat的問題

4.1 32位和64位應(yīng)用兼容問題

在HP-UX平臺上,如果同時運行32位應(yīng)用和64位應(yīng)用,而且它們訪問的是一個相同的共享內(nèi)存區(qū),則會遇到兼容性問題。

在HP-UX中,應(yīng)用程序設(shè)置IPC_CREAT標志調(diào)用shmget,所創(chuàng)建的共享內(nèi)存區(qū),只可被同類型的應(yīng)用所訪問;即32位應(yīng)用程序所創(chuàng)建的共享內(nèi)存區(qū)只可被其它的32位應(yīng)用程序訪問,同樣地,64位應(yīng)用程序所創(chuàng)建的共享內(nèi)存區(qū)只可被其它的64位應(yīng)用程序訪問。

如果,32位應(yīng)用企圖訪問一個由64位應(yīng)用創(chuàng)建的共享內(nèi)存區(qū),則會在調(diào)用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位應(yīng)用創(chuàng)建共享內(nèi)存時,合并IPC_CREAT標志,同時給定IPC_SHARE32標志:

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

對于32位應(yīng)用,沒有設(shè)定IPC_SHARE32標志的要求,但設(shè)置該標志并不會帶來任何問題,也就是說無論應(yīng)用程序?qū)⒈痪幾g為32位還是64位模式,都可采用如上相同的代碼;并且由此解決32位應(yīng)用和64位應(yīng)用在共享內(nèi)存訪問上的兼容性問題。

4.2 對同一共享內(nèi)存的連接數(shù)限制

在HP-UX上,應(yīng)用進程對同一個共享內(nèi)存區(qū)的連接次數(shù)被限制為最多1次;區(qū)別于上面第3節(jié)所介紹的AIX上的連接數(shù)限制,HP-UX并未對指向不同共享內(nèi)存區(qū)的連接數(shù)設(shè)置上限,也就是說,運行在HP-UX上的應(yīng)用進程可以同時連接很多個不同的共享內(nèi)存區(qū),但對于同一個共享內(nèi)存區(qū),最多只允許連接1次;否則,shmat調(diào)用將失敗,返回錯誤碼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.

這個限制會對多線程應(yīng)用帶來無法避免的問題,只要一個應(yīng)用進程中有超過1個以上的線程企圖連接同一個共享內(nèi)存區(qū),則都將以失敗而告終。

解決這個問題,需要修改應(yīng)用程序設(shè)計,使應(yīng)用進程具備對同一共享內(nèi)存的多線程訪問能力。相對于前述問題的解決方法,解決這個問題的方法要復(fù)雜一些。

作為可供參考的方法之一,以下介紹的邏輯可以很好地解決這個問題:

基本思路是,對于每一個共享內(nèi)存區(qū),應(yīng)用進程首次連接上之后,將其鍵值(ftok的返回值)、系統(tǒng)標識符(shmid,shmget調(diào)用的返回值)和訪問地址(即shmat調(diào)用的返回值)保存下來,以這個進程的全局數(shù)組或者鏈表的形式留下記錄。在任何對共享內(nèi)存的連接操作之前,程序都將先行檢索這個記錄列表,根據(jù)鍵值和標志符去匹配希望訪問的共享內(nèi)存,如果找到匹配記錄,則從記錄中直接讀取訪問地址,而無需再次調(diào)用shmat函數(shù),從而解決這一問題;如果沒有找到匹配目標,則調(diào)用shmat建立連接,并且為新連接上來的共享內(nèi)存添加一個新記錄。

記錄條目的數(shù)據(jù)結(jié)構(gòu),可定義為如下形式:

typedef struct _Shared_Memory_Record{key_tmem_key;// key generated by ftok()intmem_id;// id returned by shmget()void*mem_addr;// access address returned by shmat()intnattach;// times of attachment} Shared_Memory_Record;

其中,nattach成員的作用是,記錄當前對該共享內(nèi)存區(qū)的連接數(shù)目;每一次打開共享內(nèi)存的操作都將對其進行遞增,而每一次關(guān)閉共享內(nèi)存的操作將其遞減,直到nattach的數(shù)值降到0,則對該共享內(nèi)存區(qū)調(diào)用shmdt進行真正的斷開連接。

打開共享內(nèi)存的邏輯流程可參考如下圖一:

圖一

關(guān)閉共享內(nèi)存的邏輯流程可參考如下圖二:

圖二

5. Solaris中的shmdt函數(shù)原型問題

Solaris系統(tǒng)中的shmdt調(diào)用,在原型上與System V標準有所不同,

Default int shmdt(char *shmaddr);

即形參shmaddr的數(shù)據(jù)類型在Solaris上是char *,而System V定義的是void * 類型;實際上Solaris上shmdt調(diào)用遵循的函數(shù)原型規(guī)范是SVID-v4之前的標準;以Linux系統(tǒng)為例,libc4和libc5 采用的是char * 類型的形參,而遵循SVID-v4及后續(xù)標準的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_MEMORYshmdt((char *)mem_addr);#else shmdt((void *)mem_addr);#endif

6. 通過shmctl刪除共享內(nèi)存的風險

當進程斷開與共享內(nèi)存區(qū)的連接后,一般通過如下代碼刪除該共享內(nèi)存:

shmctl(mem_id, IPC_RMID, NULL);

從HP-UX上shmctl函數(shù)的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平臺也有類似的說明。關(guān)于shmctl的IPC_RMID操作,其使用特點可簡述如下:

如果共享內(nèi)存已經(jīng)與所有訪問它的進程斷開了連接,則調(diào)用IPC_RMID子命令后,系統(tǒng)將立即刪除共享內(nèi)存的標識符,并刪除該共享內(nèi)存區(qū),以及所有相關(guān)的數(shù)據(jù)結(jié)構(gòu);

如果仍有別的進程與該共享內(nèi)存保持連接,則調(diào)用IPC_RMID子命令后,該共享內(nèi)存并不會被立即從系統(tǒng)中刪除,而是被設(shè)置為IPC_PRIVATE狀態(tài),并被標記為"已被刪除";直到已有連接全部斷開,該共享內(nèi)存才會最終從系統(tǒng)中消失。

于是,存在這樣的一種狀態(tài):

N個進程(進程1至進程N)已經(jīng)與某共享內(nèi)存區(qū)連接;

進程1已完成對此共享內(nèi)存的操作,斷開連接后,調(diào)用shmctl的IPC_RMID子命令,企圖刪除該共享內(nèi)存;

由于進程2至進程N仍保持與該共享內(nèi)存的連接,因此在它們?nèi)繑嚅_連接之前,這個共享內(nèi)存區(qū)毫無疑問地會依然存在。

此時,如果有其它的進程(比如第N+1號進程)想建立對這個共享內(nèi)存的連接,是否能夠成功呢?

類似的狀態(tài),在Windows上同樣存在,只是程序借助的API有所不同,比如通過CreateFileMapping函數(shù)創(chuàng)建共享內(nèi)存,通過MapViewOfFile函數(shù)建立連接,通過UnmapViewOfFile函數(shù)斷開連接,通過CloseHandle函數(shù)刪除共享內(nèi)存等。在Windows上,對此問題的回答是肯定的;也就是說,只要共享內(nèi)存依然存在,則進程總是可以建立對它的連接,而無論之前是否有進程對其執(zhí)行過刪除操作。

然而,對于包括AIX、Solaris、HP-UX等在內(nèi)的UNIX平臺,答案卻是否定的!這也正是本節(jié)所討論的使用shmctl中的風險所在;通過以下test03.P1.c和test03.P2.c兩個例程,我們可以很直觀地得到答案:

test03.P1.c: 創(chuàng)建共享內(nèi)存,并建立連接,保持10秒后(在此期間,test03.P2將反復(fù)連接、并刪除該共享內(nèi)存),斷開連接,并最后再次嘗試連接以驗證該共享內(nèi)存是否已被真正刪除;

test03.P2.c: 反復(fù)連接由test03.P1創(chuàng)建的共享內(nèi)存,并在期間通過shmctl的IPC_RMID 子命令刪除該共享內(nèi)存,以觀察共享內(nèi)存被執(zhí)行刪除操作之后,在被徹底銷毀之前是否還能接受連接;

/******* 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;intisAttached = 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:%dn", argv[0], errno);else {isAttached = 1;printf("%s, +.Successfully attached shared memoryn", 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);" ifon Solarisshmdt((void *)mem_addr);printf("%s, -.Successfully detached shared memoryn", 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:%dn",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;inti, isAttached;mem_key = ftok("/tmp/mykeyfile", 1);mem_id = shmget(mem_key, 0, 0);// repeated attaching & detachingfor (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:%dn", 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 Solarisshmdt((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=%dn",argv[0], i, errno);}}return 0;}

上述程序均可在AIX、HP-UX、Linux平臺上編譯通過;在Solaris平臺上只需按注釋提示的要求,將shmdt的參數(shù)強制為char *類型也可編譯通過(第5節(jié)中已介紹過)。

將test03.P1.c、test03.P2.c各自編譯為可執(zhí)行程序test03.P1、test03.P2,并通過下面的shell腳本:runtest,運行它們:

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

在Linux平臺(Red Hat 8.0)上的運行結(jié)果如下:

[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

根據(jù)運行結(jié)果,我們可以看到,在Linux平臺上,即便對共享內(nèi)存執(zhí)行了刪除操作(在第5次連接之后,test03.P2進程調(diào)用了shmctl的IPC_RMID刪除操作),只要該共享內(nèi)存依然存在(test03.P1進程保持著連接,因此共享內(nèi)存不會被立即刪除),則它仍然是可連接的(test03.P2進程的第6到第9次連接均是成功的)。

然而,在AIX、HP-UX、Solaris平臺上的運行結(jié)果卻不同于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

根據(jù)結(jié)果,可以發(fā)現(xiàn),test03.P2進程的第6到第9次連接都是失敗的,也就說明,在AIX、HP-UX、Solaris平臺上一旦通過shmctl對共享內(nèi)存進行了刪除操作,則該共享內(nèi)存將不能再接受任何新的連接,即使它依然存在于系統(tǒng)中!

而且,上面的運行結(jié)果,也證明了,對共享內(nèi)存進行了刪除操作之后,當已有的連接全部斷開,該共享內(nèi)存將被系統(tǒng)自動銷毀(運行結(jié)果的最后一行,說明該共享內(nèi)存已經(jīng)不存在了)。

本節(jié)的目的在于說明,在AIX、HP-UX、Solaris平臺上調(diào)用shmctl的IPC_RMID刪除操作,是存在潛在風險的,需要足夠的謹慎。

如果,可以確知,在刪除之后不可能再有新的連接,則執(zhí)行刪除操作是安全的;

否則,在刪除操作之后如仍有新的連接發(fā)生,則這些連接都將失??!

7. 結(jié)論

對共享內(nèi)存的操作,往往是產(chǎn)品或者應(yīng)用中數(shù)據(jù)傳輸?shù)幕A(chǔ),對其可靠性和性能至關(guān)重要;而且作為底層的IPC機制,相關(guān)代碼具有不易調(diào)試的特點,由其造成的問題往往關(guān)鍵卻不容易解決。

本文從應(yīng)用實現(xiàn)的角度上,對在UNIX/Linux平臺上使用共享內(nèi)存可能會遇到的問題,進行了全面的介紹和分析,并給出了解決方法或建議,可供相關(guān)的應(yīng)用開發(fā)人員參考。

標簽: Unix系統(tǒng)
主站蜘蛛池模板: 真实国产乱子伦精品一区二区三区 | 免费在线看a | 中国特级毛片 | 亚洲精品一二三四 | 亚洲欧美专区精品伊人久久 | www日韩在线 | 小明看看成人免费视频 | 亚洲欧美日韩精品一区 | 久久精品毛片 | 成在线人免费视频 | 91精品天美精东蜜桃传媒免费 | 亚洲爱婷婷色婷婷五月 | 欧美黄色片在线观看 | 亚洲欧美日韩国产精品26u | 国产精品小视频在线观看 | 91国内精品久久久久影院优播 | 91短视频版官网 | 亚洲欧美视频网站 | 欧美日韩亚洲一区二区精品 | 成人嗯啊视频在线观看 | 小明www永久在线看 小明www永久免费播放平台 | 国产亚洲精品美女一区二区 | 成人午夜爽爽爽免费视频 | 亚洲午夜精品一区二区蜜桃 | 成人a视频在线观看 | 国内一区二区三区精品视频 | 欧美视频一区二区三区 | 国产在线精品一区二区高清不卡 | 中文字幕 亚洲一区 | 青青青国产精品国产精品久久久久 | 日本xxxwww免费视频软件 | 国产一区二区在线播放 | 欧美国产综合视频在线观看 | 13一14周岁毛片免费 | 亚洲在线播放视频 | 91亚洲精品一区二区在线观看 | 亚洲 日本 欧美 中文幕 | 欧美夜夜精品一级爽 | 欧美日韩亚洲国内综合网俺 | 亚洲日韩中文字幕在线播放 | 男人都懂www深夜免费网站 |