當前位置:首頁 » 硬碟大全 » 共享內存緩存機制
擴展閱讀
訪問海外網路加速器 2022-08-14 21:20:55
怎麼打開電腦賬戶配置 2022-08-14 21:18:43
如何能拿到別人郵箱密碼 2022-08-14 21:18:42

共享內存緩存機制

發布時間: 2022-07-06 20:21:42

『壹』 linux 進程間通信的幾種方式

第一種:管道通信
兩個進程利用管道進行通信時,發送信息的進程稱為寫進程;接收信息的進程稱為讀進程。管道通信方式的中間介質就是文件,通常稱這種文件為管道文件,它就像管道一樣將一個寫進程和一個讀進程連接在一起,實現兩個進程之間的通信。寫進程通過寫入端往管道文件中寫入信息;讀進程通過讀出端從管道文件中讀取信息。兩個進程協調不斷地進行寫和讀,便會構成雙方通過管道傳遞信息的流水線。
第二種:消息緩沖通信
多個獨立的進程之間可以通過消息緩沖機制來相互通信。這種通信的實現是以消息緩沖區為中間介質,通信雙方的發送和接收操作均以消息為單位。在存儲器中,消息緩沖區被組織成隊列,通常稱之為消息隊列。消息隊列一旦創建後即可由多進程共享,發送消息的進程可以在任意時刻發送任意個消息到指定的消息隊列上,並檢查是否有接收進程在等待它所發送的消息。若有則喚醒它,而接收消息的進程可以在需要消息的時候到指定的消息隊列上獲取消息,如果消息還沒有到來,則轉入睡眠等待狀態。
第三種:共享內存通信
針對消息緩沖需要佔用CPU進行消息復制的缺點,OS提供了一種進程間直接進行數據交換的通信方式。共享內存,顧名思義這種通信方式允許多個進程在外部通信協議或同步,互斥機制的支持下使用同一個內存段進行通信,它是一種最有效的數據通信方式,其特點是沒有中間環節,直接將共享的內存頁面通過附接映射到相互通信的進程各自的虛擬地址空間中,從而使多個進程可以直接訪問同一個物理內存頁面。

『貳』 請問請問linux共享內存的鍵(IPC的對象名)與共享內存標示符有什麼區別

共享內存指在多處理器的計算機系統中,可以被不同中央處理器(CPU)訪問的大容量內存。由於多個CPU需要快速訪問存儲器,這樣就要對存儲器進行緩存(Cache)。任何一個緩存的數據被更新後,由於其他處理器也可能要存取,共享內存就需要立即更新,否則不同的處理器可能用到不同的數據。共享內存 (shared memory)是 Unix下的多進程之間的通信方法 ,這種方法通常用於一個程序的多進程間通信,實際上多個程序間也可以通過共享內存來傳遞信息。

共享內存的創建
共享內存是存在於內核級別的一種資源,在shell中可以使用ipcs命令來查看當前系統IPC中的狀態,在文件系統/proc目錄下有對其描述的相應文件。函數shmget可以創建或打開一塊共享內存區。函數原型如下: #include <sys/shm.h> int shmget( key_t key, size_t size, int flag ); 函數中參數key用來變換成一個標識符,而且每一個IPC對象與一個key相對應。當新建一個共享內存段時,size參數為要請求的內存長度(以位元組為單位)。 注意:內核是以頁為單位分配內存,當size參數的值不是系統內存頁長的整數倍時,系統會分配給進程最小的可以滿足size長的頁數,但是最後一頁的剩餘部分內存是不可用的。 當打開一個內存段時,參數size的值為0。參數flag中的相應許可權位初始化ipc_perm結構體中的mode域。同時參數flag是函數行為參數,它指定一些當函數遇到阻塞或其他情況時應做出的反應。shmid_ds結構初始化如表14-4所示。
編輯本段初始化
shmid_ds結構數據 初 值 shmid_ds結構數據 初 值
shm_lpid 0 shm_dtime 0
shm_nattach 0 shm_ctime 系統當前值
shm_atime 0 shm_segsz 參數 size
下面實例演示了使用shmget函數創建一塊共享內存。程序中在調用shmget函數時指定key參數值為IPC_PRIVATE,這個參數的意義是創建一個新的共享內存區,當創建成功後使用shell命令ipcs來顯示目前系統下共享內存的狀態。命令參數-m為只顯示共享內存的狀態。 (1)在vi編輯器中編輯該程序如下: 程序清單14-8 create_shm.c 使用shmget函數創建共享內存 #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <stdlib.h> #include <stdio.h> #define BUFSZ 4096 int main ( void ) printf ( "successfully created segment : %d \n", shm_id ) ; system( "ipcs -m"); /*調用ipcs命令查看IPC*/ exit( 0 ); } (2)在shell中編譯該程序如下: $gcc create_shm.c–o create_shm (3)在shell中運行該程序如下: $./ create_shm successfully created segment : 2752516 ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0x00000000 65536 root 600 393216 2 dest 0x00000000 2654209 root 666 4096 0 0x0056a4d5 2686978 root 600 488 1 0x0056a4d6 2719747 root 600 131072 1 0x00000000 2752516 root 666 4096 0 上述程序中使用shmget函數來創建一段共享內存,並在結束前調用了系統shell命令ipcs –m來查看當前系統IPC狀態。
編輯本段共享內存的操作
由於共享內存這一特殊的資源類型,使它不同於普通的文件,因此,系統需要為其提供專有的操作函數,而這無疑增加了程序員開發的難度(需要記憶額外的專有函數)。使用函數shmctl可以對共享內存段進行多種操作,其函數原型如下: #include <sys/shm.h> int shmctl( int shm_id, int cmd, struct shmid_ds *buf ); 函數中參數shm_id為所要操作的共享內存段的標識符,struct shmid_ds型指針參數buf的作用與參數cmd的值相關,參數cmd指明了所要進行的操作,其解釋如表14-5所示。
編輯本段cmd參數詳解
cmd的值 意 義
IPC_STAT 取shm_id所指向內存共享段的shmid_ds結構,對參數buf指向的結構賦值
IPC_SET 使用buf指向的結構對sh_mid段的相關結構賦值,只對以下幾個域有作用,shm_perm. uid shm_perm.gid以及shm_perm.mode 注意此命令只有具備以下條件的進程才可以請求: 1.進程的用戶ID等於shm_perm.cuid或者等於shm_perm.uid 2.超級用戶特權進程
IPC_RMID 刪除shm_id所指向的共享內存段,只有當shmid_ds結構的shm_nattch域為零時,才會真正執行刪除命令,否則不會刪除該段 注意此命令的請求規則與IPC_SET命令相同
SHM_LOCK 鎖定共享內存段在內存,此命令只能由超級用戶請求
SHM_UNLOCK 對共享內存段解鎖,此命令只能由超級用戶請求
使用函數shmat將一個存在的共享內存段連接到本進程空間,其函數原型如下: #include <sys/shm.h> void *shmat( int shm_id, const void *addr, int flag ); 函數中參數shm_id指定要引入的共享內存,參數addr與flag組合說明要引入的地址值,通常只有2種用法,addr為0,表明讓內核來決定第1個可以引入的位置。addr非零,並且flag中指定SHM_RND,則此段引入到addr所指向的位置(此操作不推薦使用,因為不會只對一種硬體上運行應用程序,為了程序的通用性推薦使用第1種方法),在flag參數中可以指定要引入的方式(讀寫方式指定)。 %說明:函數成功執行返回值為實際引入的地址,失敗返回–1。shmat函數成功執行會將shm_id段的shmid_ds結構的shm_nattch計數器的值加1。 當對共享內存段操作結束時,應調用shmdt函數,作用是將指定的共享內存段從當前進程空間中脫離出去。函數原型如下: #include <sys/shm.h> int shmdt( void *addr); 參數addr是調用shmat函數的返回值,函數執行成功返回0,並將該共享內存的shmid_ds結構的shm_nattch計數器減1,失敗返回–1。 下面實例演示了操作共享內存段的流程。程序的開始部分先檢測用戶是否有輸入,如出錯則列印該命令的使用幫助。接下來從命令行讀取將要引入的共享內存ID,使用shmat函數引入該共享內存,並在分離該內存之前睡眠3秒以方便查看系統IPC狀態。 (1)在vi編輯器中編輯該程序如下: 程序清單14-9 opr_shm.c 操作共享內存段 #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <stdlib.h> #include <stdio.h> int main ( int argc, char *argv[] ) shm_id = atoi(argv[1]); /*得到要引入的共享內存段*/ /*引入共享內存段,由內核選擇要引入的位置*/ if ( (shm_buf = shmat( shm_id, 0, 0)) < (char *) 0 ) printf ( " segment attached at %p\n", shm_buf ); /*輸出導入的位置*/ system("ipcs -m"); sleep(3); /* 休眠 */ if ( (shmdt(shm_buf)) < 0 ) printf ( "segment detached \n" ); system ( "ipcs -m " ); /*再次查看系統IPC狀態*/ exit ( 0 ); } (2)在shell中編譯該程序如下: $gcc opr_shm.c–o opr_shm (3)在shell中運行該程序如下: $./ opr_shm 2752516 segment attached at 0xb7f29000 ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0x00000000 65536 root 600 393216 2 dest 0x00000000 2654209 root 666 4096 0 0x0056a4d5 2686978 root 600 488 1 0x0056a4d6 2719747 root 600 131072 1 0x00000000 2752516 root 666 4096 1 segment detached ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0x00000000 65536 root 600 393216 2 dest 0x00000000 2654209 root 666 4096 0 0x0056a4d5 2686978 root 600 488 1 0x0056a4d6 2719747 root 600 131072 1 0x00000000 2752516 root 666 4096 0 上述程序中從命令行中讀取所要引入的共享內存ID,並使用shmat函數引入該內存到當前的進程空間中。注意在使用shmat函數時,將參數addr的值設為0,所表達的意義是由內核來決定該共享內存在當前進程中的位置。由於在編程的過程中,很少會針對某一個特定的硬體或系統編程,所以由內核決定引入位置也就是shmat推薦的使用方式。在導入後使用shell命令ipcs –m來顯示當前的系統IPC的狀態,可以看出輸出信息中nattch欄位為該共享內存時的引用值,最後使用shmdt函數分離該共享內存並列印系統IPC的狀態。
編輯本段共享內存使用注意事項
共享內存相比其他幾種方式有著更方便的數據控制能力,數據在讀寫過程中會更透明。當成功導入一塊共享內存後,它只是相當於一個字元串指針來指向一塊內存,在當前進程下用戶可以隨意的訪問。缺點是,數據寫入進程或數據讀出進程中,需要附加的數據結構控制,共享內存通信數據結構示意如圖14-9所示。
編輯本段結構示意
%說明:圖中兩個進程同時遵循一定的規則來讀寫該內存。同時,在多進程同步或互斥上也需要附加的代碼來輔助共享內存機制。 在共享內存段中都是以字元串的默認結束符為一條信息的結尾。每個進程在讀寫時都遵守這個規則,就不會破壞數據的完整性。
另外,站長團上有產品團購,便宜有保證

『叄』 比較Linux與Unix操作系統,也可以比較Linux與最新的Windows伺服器操作系統。從性能和價格兩方面進行比較。

Linux是一個主要運行於inetel架構的UNIX-like操作系統,它不僅具備UNIX系統的全部特徵,而且與POSIX標准兼容。Linux的功能包括真正的多任務、虛擬內存、共享庫、需求裝載、共享的寫時復製程序執行、優秀的內存管理以及TCP/IP網路支持等。它的發行遵守GNU的通用公共許可證。而Windows 操作系統卻和Linux有著完全不同的開發模式和發展歷史。
進程管理及調度:Linux開銷較小
在進程管理及調度方面,Linux是一個單塊式的操作系統,操作系統通常在用戶進程的內存空間內進行,可免去發生系統調用時的進程切換開銷。Windows是一個准微內核操作系統,許多功能以單獨的進程實現,從而提高了系統的模塊化程度,但進程切換上的開銷要大一些。
Linux支持內核級的線程,但它將線程定義為進程的另一個「執行上下文」,從而簡化了進程/線程之間的關系和調度程序的設計,它的線程庫提供了和POSIX兼容的線程同步機制。Windows支持的線程是典型的進程/線程模型。它的線程同步機制和Linux類似。Linux中進程是基本的調度單位,它提供了三種調度策略。
進程間通信機制:Linux更靈活
在進程間通信機制上,Linux提供了標準的UNIX IPC機制,而Windows 則在基本IPC機制的基礎上,提供了許多直接面向應用程序的高級IPC機制。從本質上看,Linux的IPC機制接近於IPC原語,比較底層,提供了最大的靈活性,也可以在此基礎上建立更加復雜的高級IPC機制,而Windows 在原語級提供的IPC機制有管道、命名管道、消息傳遞、共享內存、信號量等。
內存管理:Linux優於Windows
在內存管理上,Linux 和Windows 在面對相同的進程地址空間大小時,對內存布局的使用方式不同。Windows實際只為進程准備了2GB弱的可用虛擬地址空間,而Linux中的進程地址空間使用更靈活些。
在虛擬內存的使用上,Linux內核為用戶管理了非常多的細節問題,用戶可以認為自己真正擁有4GB地址空間,而不用關心虛擬內存是否提交物理存儲等問題。Windows為程序員提供了多種虛擬內存使用方案,雖然這些方案的使用有些復雜,但卻提供了一定程度上的靈活性。它也支持DOS和Win16程序的執行,但為了提供這種兼容性,它的內存管理付出了極高的性能代價。
Linux 和Windows雖然均提供了內存共享技術,但它們的實現有些細微的差別。Linux提供給用戶的介面非常簡單,只需將自己的虛擬內存空間區域附加到共享內存對象之上。Windows則是通過內存映射文件提供共享內存機制,從使用上講,略顯復雜。
Linux的內存交換管理靈活性很強,用戶可以在普通的文件系統上建立「無洞」的文件作為交換空間,還可以使用多個交換文件,從而可以動態增加交換文件。它也提供了利用交換分區作為交換空間的方法,此方法是優選的交換空間方案。Windows 的頁面文件很難擺脫碎片化的危險,為了保證它採用無碎片的頁面文件,必須採取一定的措施。
Linux 和Windows 在高速緩存的使用上有一些共同之處,均盡量採用系統的全部空閑RAM作為高速緩存區域,但Linux在高速緩存管理上有一些獨到之處,這是它性能之所以高的根本原因所在。
安全性:Linux具有一定優勢
在安全性方面,Linux採用的是UNIX在安全性方面成功的技術,盡管有一些安全漏洞,但因為設計上的開放性,這些漏洞能夠在很快的時間內發現並得到解決。Windows 雖然採用的ACL技術,更加復雜和嚴密,但因為其密碼加密步驟過於簡單,密碼容易被破解。安全性設計上的不公開性也導致其有很多安全上的漏洞。
一項最新的測試結果表明,採用linux下的samba文件伺服器與windows 2003 server文件伺服器性能比較,linux的表現是非常令人滿意的。
原文地址:http://server.zol.com.cn/77/773618.html

『肆』 redis等內存資料庫可否代替共享內存作為進

mongodb和memcached不是一個范疇內的東西。mongodb是文檔型的非關系型資料庫,其優勢在於查詢功能比較強大,能存儲海量數據。mongodb和memcached不存在誰替換誰的問題。 和memcached更為接近的是redis。它們都是內存型資料庫,數據保存在內存中,通過tcp直接存取,優勢是速度快,並發高,缺點是數據類型有限,查詢功能不強,一般用作緩存。在我們團隊的項目中,一開始用的是memcached,後來用redis替代。 相比memcached: 1、redis具有持久化機制,可以定期將內存中的數據持久化到硬碟上。 2、redis具備binlog功能,可以將所有操作寫入日誌,當redis出現故障,可依照binlog進行數據恢復。 3、redis支持virtual memory,可以限定內存使用大小,當數據超過閾值,則通過類似LRU的演算法把內存中的最不常用數據保存到硬碟的頁面文件中。 4、redis原生支持的數據類型更多,使用的想像空間更大。 5、前面有位朋友所提及的一致性哈希,用在redis的sharding中,一般是在負載非常高需要水平擴展時使用。我們還沒有用到這方面的功能,一般的項目,單機足夠支撐並發了。redis 3.0將推出cluster,功能更加強大。 6、redis更多優點,請移步官方網站查詢。

『伍』 linux共享內存和mmap的區別

共享內存的創建
根據理論:
1. 共享內存允許兩個或多個進程共享一給定的存儲區,因為數據不需要來回復制,所以是最快的一種進程間通信機制。共享內存可以通過mmap()映射普通文件(特殊情況下還可以採用匿名映射)機制實現,也可以通過系統V共享內存機制實現。應用介面和原理很簡單,內部機制復雜。為了實現更安全通信,往往還與信號燈等同步機制共同使用。

mmap的機制如:就是在磁碟上建立一個文件,每個進程存儲器裡面,單獨開辟一個空間來進行映射。如果多進程的話,那麼不會對實際的物理存儲器(主存)消耗太大。

shm的機制:每個進程的共享內存都直接映射到實際物理存儲器裡面。

結論:

1、mmap保存到實際硬碟,實際存儲並沒有反映到主存上。優點:儲存量可以很大(多於主存)(這里一個問題,需要高手解答,會不會太多拷貝到主存裡面???);缺點:進程間讀取和寫入速度要比主存的要慢。

2、shm保存到物理存儲器(主存),實際的儲存量直接反映到主存上。優點,進程間訪問速度(讀寫)比磁碟要快;缺點,儲存量不能非常大(多於主存)

使用上看:如果分配的存儲量不大,那麼使用shm;如果存儲量大,那麼使用shm。

參看網路:http://ke..com/view/1499209.htm
mmap就是一個文件操作

看這些網路的描述:
mmap()系統調用使得進程之間通過映射同一個普通文件實現共享內存。普通文件被映射到進程地址空間後,進程可以向訪問普通內存一樣對文件進行訪問,不必再調用read(),write()等操作。 成功執行時,mmap()返回被映射區的指針,munmap()返回0。失敗時,mmap()返回MAP_FAILED[其值為(void *)-1],munmap返回-1。errno被設為以下的某個值 EACCES:訪問出錯EAGAIN:文件已被鎖定,或者太多的內存已被鎖定EBADF:fd不是有效的文件描述詞EINVAL:一個或者多個參數無效 ENFILE:已達到系統對打開文件的限制ENODEV:指定文件所在的文件系統不支持內存映射ENOMEM:內存不足,或者進程已超出最大內存映射數量 EPERM:權能不足,操作不允許ETXTBSY:已寫的方式打開文件,同時指定MAP_DENYWRITE標志SIGSEGV:試著向只讀區寫入 SIGBUS:試著訪問不屬於進程的內存區參數fd為即將映射到進程空間的文件描述字,

一般由open()返回,同時,fd可以指定為-1,此時須指定 flags參數中的MAP_ANON,表明進行的是匿名映射(不涉及具體的文件名,避免了文件的創建及打開,很顯然只能用於具有親緣關系的進程間通信)

相關文章參考:
mmap函數是unix/linux下的系統調用,來看《Unix Netword programming》卷二12.2節有詳細介紹。
mmap系統調用並不是完全為了用於共享內存而設計的。它本身提供了不同於一般對普通文件的訪問方式,進程可以像讀寫內存一樣對普通文件的操作。而Posix或系統V的共享內存IPC則純粹用於共享目的,當然mmap()實現共享內存也是其主要應用之一。
mmap系統調用使得進程之間通過映射同一個普通文件實現共享內存。普通文件被映射到進程地址空間後,進程可以像訪問普通內存一樣對文件進行訪問,不必再 調用read(),write()等操作。mmap並不分配空間, 只是將文件映射到調用進程的地址空間里, 然後你就可以用memcpy等操作寫文件, 而不用write()了.寫完後用msync()同步一下, 你所寫的內容就保存到文件里了. 不過這種方式沒辦法增加文件的長度, 因為要映射的長度在調用mmap()的時候就決定了.

簡單說就是把一個文件的內容在內存裡面做一個映像,內存比磁碟快些。
基本上它是把一個檔案對應到你的virtual memory 中的一段,並傳回一個指針。

重寫總結:
1、mmap實際就是操作「文件」。
2、映射文件,除了主存的考慮外。shm的內存共享,效率應該比mmap效率要高(mmap通過io和文件操作,或「需要寫完後用msync()同步一下」);當然mmap映射操作文件,比直接操作文件要快些;由於多了一步msync應該可以說比shm要慢了吧???
3、另一方面,mmap的優點是,操作比shm簡單(沒有調用比shm函數復雜),我想這也是許多人喜歡用的原因,包括nginx。

缺點,還得通過實際程序測試,確定!!!

修正理解(這也真是的,這個網站沒辦法附加;只能重寫了):
今天又細心研究了一下,發現網路這么一段說明:
2、系統調用mmap()用於共享內存的兩種方式:
(1)使用普通文件提供的內存映射:適用於任何進程之間;此時,需要打開或創建一個文件,然後再調用mmap();典型調用代碼如下:
fd=open(name, flag, mode);
if(fd<0)
...
ptr=mmap(NULL, len , PROT_READ|PROT_WRITE, MAP_SHARED , fd , 0); 通過mmap()實現共享內存的通信方式有許多特點和要注意的地方,我們將在範例中進行具體說明。
(2)使用特殊文件提供匿名內存映射:適用於具有親緣關系的進程之間;由於父子進程特殊的親緣關系,在父進程中先調用mmap(),然後調用fork()。那麼在調用fork()之後,子進程繼承父進程匿名映射後的地址空間,同樣也繼承mmap()返回的地址,這樣,父子進程就可以通過映射區域進行通信了。注意,這里不是一般的繼承關系。一般來說,子進程單獨維護從父進程繼承下來的一些變數。而mmap()返回的地址,卻由父子進程共同維護。
看了一下windows「內存映射文件」:http://ke..com/view/394293.htm
內存映射文件與虛擬內存有些類似,通過內存映射文件可以保留一個地址空間的區域,同時將物理存儲器提交給此區域,只是內存文件映射的物理存儲器來自一個已經存在於磁碟上的文件,而非系統的頁文件,而且在對該文件進行操作之前必須首先對文件進行映射,就如同將整個文件從磁碟載入到內存。由此可以看出,使用內存映射文件處理存儲於磁碟上的文件時,將不必再對文件執行I/O操作,這意味著在對文件進行處理時將不必再為文件申請並分配緩存,所有的文件緩存操作均由系統直接管理,由於取消了將文件數據載入到內存、數據從內存到文件的回寫以及釋放內存塊等步驟,使得內存映射文件在處理大數據量的文件時能起到相當重要的作用。另外,實際工程中的系統往往需要在多個進程之間共享數據,如果數據量小,處理方法是靈活多變的,如果共享數據容量巨大,那麼就需要藉助於內存映射文件來進行。實際上,內存映射文件正是解決本地多個進程間數據共享的最有效方法。

這里再總結一次:
1、mmap有兩種方式,一種是映射內存,它把普通文件映射為實際物理內存頁,訪問它就和訪問物理內存一樣(這也就和shm的功能一樣了)(同時不用刷新到文件)
2、mmap可以映射文件,不確定會不會像windows「內存映射文件」一樣的功能,如果是,那麼他就能映射好幾G甚至好幾百G的內存數據,對大數據處理將提供強大功能了???
3、shm只做內存映射,和mmap第一個功能一樣!只不過不是普通文件而已,但都是物理內存。

『陸』 怎麼利用設計模式來更有效的使用共享內存

IOCTL 方法:應用程序分配共享內存

在用戶模式與核心模式之間共享內存的最簡單有效的方法是使用 IOCTL。IOCTL 有四種不同的類型,下列三種 IOCTL 使您可以在設備驅動程序中直接訪問用戶緩沖區:

METHOD_IN_DIRECT
METHOD_OUT_DIRECT
METHOD_NEITHER
在以上這些方法中沒有創建中間系統緩沖區。

METHOD_IN_DIRECT 和 METHOD_OUT_DIRECT 自動在 DeviceIoControl 中鎖定用戶指定的緩沖區,並為驅動程序創建內存描述列表 (MDL)。驅動程序可以從 MDL 得到一個系統地址,並根據 IOCTL 傳輸類型將信息傳入傳出緩沖區。由於所有的緩沖區驗證、鎖定及 MDL 創建均是通過 I/O 管理器來完成的,所以這是一種簡單的方法。

相反,METHOD_NEITHER 直接將用戶緩沖區提供給驅動程序,驅動程序必須適當地驗證緩沖區並鎖定緩沖區,如果需要,還要為緩沖區獲取一個系統地址。雖然這是通過設備驅動程序 I/O 子系統的最快捷路徑,但使用這種方法時也有一些應當注意的問題。有關其它信息,請參見 Microsoft Knowledge Base 中的下列文章:

Q126416 INFO:使用 METHOD_NEITHER IOCTL 的警告
要了解這三種不同的 IOCTL 如何工作,請參見以下 Microsoft Knowledge Base 文章:

Q178317 文件:IOCTL.exe:如何使用不同類型的 IOCTL
MmMapLockedPages 方法:設備驅動程序分配共享內存

在這種方法中,驅動程序通過 MmAllocateContiguousMemory 或 ExAllocatePoolXxx 函數分配內存,創建並建立描述緩沖區的 MDL,並使用 MmMapLockedPages 把內存映射到用戶進程地址空間中。用戶應用程序可以使用由 MmMapLockPages 返回的虛擬地址直接訪問系統內存。

由於應當在訪問內存的進程上下文中完成映射,所以此方法只能用於單層結構的驅動程序,這時可以保證 dispatch 常式在調用進程上下文中運行。您可以在任意數量的用戶過程地址空間上映射同一個系統緩沖區。不過,應當設計一種保護機制,使驅動程序及所有應用程序對內存的訪問同步。進一步說,應當在終止進程之前或者一旦使用完緩沖區就在映射緩沖區的相同進程上下文中取消緩沖區的映射。下面介紹將驅動程序緩沖區映射至某個用戶進程時需採取的步驟:

首先如下分配內存:

SystemVirtualAddress = MmAllocateContiguousMemory(NumberOfBytes,
HighestAcceptableAddress); 或
SystemVirtualAddress = ExAllocatePool(PoolType, NumberOfBytes);

如下分配一個 MDL:

Mdl = IoAllocateMdl(SystemVirtualAddress, NumberOfBytes, FALSE,
FALSE, NULL);

建立 MDL 以描述內存頁。如果已經分配了非頁面緩沖池中的內存,請使用:

MmBuildMdlForNonPagedPool(Mdl);
如果分配了頁面緩沖池中的內存,請使用:

MmProbeAndLockPages(Mdl, KernelMode, IoWriteAccess);
如下將鎖定的頁面映射至進程的用戶地址空間中:

UserVirtualAddress = MmMapLockedPages(Mdl, UserMode);

前三步可以在 DriverEntry 或 Dispatch 常式中完成。但是,將緩沖區映射至用戶地址空間的最後一步,應當在運行於調用進程上下文的某個常式(通常是單層驅動程序的 dispatch 常式)中完成。

您可以在某個提高的 IRQL 級及任何進程上下文(即中斷服務常式 (ISR) 及延遲過程調用 (DPC))的驅動程序中使用 SystemVirtualAddress,在應用程序或運行正確進程上下文的驅動程序中使用 UserVirtualAddress。

按照下列步驟取消映射並釋放緩沖區:
首先從用戶地址空間中取消頁面映射。應在映射 UserVirtualAddress 的進程上下文中運行時調用函數:
MmUnmapLockedPages(UserVirtualAddress, Mdl);
如果使用 MmProbleAndLockPages 鎖定了頁面,則使用以下函數解鎖:
MmUnlockPages(Mdl)
釋放 MDL:
IoFreeMdl(Mdl);
釋放系統內存:
MmFreeContiguousMemory(SystemVirtualAddress); 或
ExFreePool(SystemVirtualAddress);
共享內存對象方法

使用保存在頁面文件上的內存映射文件是用於在用戶進程之間共享內存的常用方法。不過,您可以使用以上技術在用戶過程及設備驅動程序之間共享內存。使用這種技術有兩種方法。在第一種方法中,驅動程序可以創建命名內存對象(稱為 section 對象),一個或多個應用程序通過使用 OpenFileMapping 打開以上對象,然後調用 MapViewOfFile 函數來得到指向它的指針。通過指定以上對象的保護屬性,可以定義某個進程使用內存的方式。

在第二種方法中,應用程序可以使用 CreateFileMapping 在用戶模式下創建一個命名內存對象。驅動程序通過使用 ZwMapViewOfSection 函數及調用 ZwMapViewOfSection 得到其指針來打開以上內存對象。您應當使用異常處理程序在核心模式中訪問該內存地址。有關使用這種技術的範例,請參見下列 Microsoft Knowledge Base 文章:

Q194945 樣例:有關在核心和用戶模式之間共享內存的 Section.exe
因為總是在進程的用戶地址空間(小於 0x80000000,不管是在核心模式還是在用戶模式中創建對象)上映射對象,所以只在進程上下文中訪問地址時地址才有效。在相同內存對象上對 MapViewOfFile 或 ZwMapViewOfSection 的每次調用將返回一個不同的內存地址,即使對於相同的進程也是如此。通常不建議使用這種方法,特別是對於低級設備驅動程序而言。如前所述,這是因為地址范圍被限制於映射對象的進程中,不能在 DPC 或 ISR 中訪問。而且,在核心模式中創建內存對象的 API 沒有記載於 DDK 中。

然而,要在提高的 IRQL (如 DPC 或 ISR)上使用該地址,您一定要查明並鎖定緩沖區頁面,並得到如 IOCTL 方法中所述的系統虛擬地址 (MmGetSystemAddressForMdl)。

只有準備在兩個(或多個)用戶進程和一個(或多個)設備驅動程序之間共享內存時,這種方法才比較簡單容易。否則,使用 IOCTL 技術在一個用戶過程及一個設備驅動程序之間共享內存將更為簡單有效。