日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

APR分析-共享内存篇

發布時間:2024/1/23 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 APR分析-共享内存篇 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

APR分析-共享內存篇

共享內存是一種重要的IPC方式。在項目中多次用到共享內存,只是用而并未深入研究。這次趁研究APR代碼的機會復習了共享內存的相關資料。

APR共享內存封裝的源代碼的位置在$(APR_HOME)/shmem目錄下,本篇blog著重分析unix子目錄下的shm.c文件內容,其相應頭文件為$(APR_HOME)/include/apr_shm.h。

一、共享內存簡單小結

共享內存是最快的IPC方式,因為一旦這樣的共享內存段映射到各個進程的地址空間,這些進程間通過共享內存的數據傳遞就不需要內核的幫忙了。Stevens的解釋是“各進程不是通過執行任何進入內核的系統調用來傳遞數據,顯然內核的責任僅僅是建立各進程地址空間與共享內存的映射,當然像處理頁面故障這一類的底層活還是要做的”。相比之下,管道和消息隊列交換數據時都需要內核來中轉數據,速度就相對較慢。

Unix"歷史悠久",所以在歷史上不同版本的Unix提供了不同的支持共享內存的方式,我想這也是Stevens在《Unix網絡編程第2卷》中花費三章來講解共享內存的原因吧。你也不妨先看看shm.c中的代碼,代碼用條件宏分割不同Share Memory的實現。

二、APR共享內存封裝

APR提供多種創建共享內存的方式,其中最主要的就是apr_shm_create接口,其偽碼如下:

apr_shm_create {if (要創建匿名shm) { #if APR_USE_SHMEM_MMAP_ZERO || APR_USE_SHMEM_MMAP_ANON #if APR_USE_SHMEM_MMAP_ZEROxxxx ----------(1) #elif APR_USE_SHMEM_MMAP_ANONxxxx ----------(2) #endif #endif /* APR_USE_SHMEM_MMAP_ZERO || APR_USE_SHMEM_MMAP_ANON */ #if APR_USE_SHMEM_SHMGET_ANONxxxx ----------(3) #endif} else { /*創建有名shm*/ #if APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM #if APR_USE_SHMEM_MMAP_TMPxxxx ----------(4) #endif #if APR_USE_SHMEM_MMAP_SHMxxxx ----------(5) #endif #endif /* APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM */ #if APR_USE_SHMEM_SHMGETxxxx ----------(6) #endif} }

apr_shm_create函數代碼很長,之所以這樣是因為其支持多種創建Share Memory的方式,在上面的偽代碼中公用條件宏分隔了6種方式,這6中方式將在下面分析。可以看出shmem主要分為"匿名的"和"有名的",其中"有名的"都是通過filename來標識(或通過ftok轉換filename而得到的shmid來標識).

其中不同版本Unix創建匿名shmem的做法如下:

(1) SVR4通過映射"/dev/zero"設備文件來獲取匿名共享內存,其代碼一般為:

fd = open("/dev/zero", ..); ptr = mmap(..., MAP_SHARED, fd, ...);

(2) 4.4 BSD提供更加簡單的方式來支持匿名共享內存(注意標志參數MAP_XX)

ptr = mmap(..., MAP_SHARED | MAP_ANON, -1, ...);

(3) System V匿名共享內存區的做法如下:

shmid = shmget(IPC_PRIVATE, ...); ptr = shmat(shmid, ...);

匿名共享內存一般都用于有親緣關系的進程間的數據通訊。由父進程創建共享內存,子進程自動繼承下來。由于是匿名,沒有親緣關系的進程是不能動態連接到該共享內存區的。

不同版本Unix創建有名shmem的做法如下:

(4)由于是有名的shmem,所以與匿名不同的地方在于用filename替代"/dev/zero"做映射。

fd = open(filename, ...); apr_file_trunc(...); ptr = mmap(..., MAP_SHARED, fd, ...);

(5) Posix共享內存的做法

fd = shm_open(filename, ...); apr_file_trunc(...); ptr = mmap(..., MAP_SHARED, fd, ...);

值得注意的一點就是通過shm_open映射的共享內存可以供無親緣關系的進程共享。apr_file_trunc用于重新設定共享內存對象長度。

(6) System V有名共享內存區的做法如下:

shmkey = ftok(filename, 1);

shmid = shmget(shmkey, ...); //相當于open orshm_open

ptr = shmat(shmid, ...); //相當于mmap

有名共享內存一般都與一個文件相關,該文件映射到共享內存段,而不同的進程(包括無親緣關系的進程)則都映射到該文件以達到目的。在APR中通過apr_shm_attach可以動態將調用進程連接到已存在的共享內存上,前提是你必須知道該共享內存區的標識,在APR中一律用filename做標識。

三、總結

內核架起了多個進程間

共享數據的紐帶--共享內存。通過上面的敘述你會發現共享內存的創建其實并不困難,真正困難的是共享內存的管理[注1],在正規的軟件公司像內存/共享內存管理這樣的重要底層功能都是封裝成庫形式的,當然內存管理的內容不是這篇blog重點涉及的內容。

四、參考資料:

1、《Unix網絡編程第2卷》

2、《Unix環境高級編程》

[注1] SIGSEGV和SIGBUS

涉及共享內存的管理就不能不提到訪問共享內存對象。談到訪問共享內存對象就要留神“SIGSEGV和SIGBUS”這兩個信號。

系統分配內存頁來承載內存映射區,由于內存頁大小是固定的,所以存在多余的頁空間空閑,比如待映射文件大小為5000 bytes,內存映射區大小也為5000

bytes。而一個內存頁大小4096,系統勢必要分配兩頁來承載,這時空閑的有效空間為從5000-8191,如果進程訪問這段地址空間也不會發生錯誤。但是要超出8191,就會收到SIGSEGV信號,導致程序停止。關于SIGBUS信號的來歷,這里也舉例說明:若待映射文件大小為5000

bytes,我們在mmap時指定內存映射區size = 15000 > 5000,這時內核真正的共享區承載體大小只有8192(能包容映射文件大小即可),此時在[0,8191]內訪問均沒問題,但在[8192,14999]之間會得到SIGBUS信號;超出15000訪問時會觸發SIGSEGV信號。

?

總結

以上是生活随笔為你收集整理的APR分析-共享内存篇的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。