歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Linux下多任務間通信和同步-mmap共享內存

Linux下多任務間通信和同步-mmap共享內存

日期:2017/3/1 9:52:07   编辑:Linux編程

1.簡介

共享內存可以說是最有用的進程間通信方式.兩個不用的進程共享內存的意思是:同一塊物理內存被映射到兩個進程的各自的進程地址空間.一個進程可以及時看到另一個進程對共享內存的更新,反之亦然.

采用共享內存通信的一個顯而易見的好處效率高,因為進程可以直接讀寫內存,而不需要任何數據的復制.對於向管道和消息隊列等通信等方式,則需要在內核和用戶空間進行四次的數據復制,而共享內存則只需要兩次數據復制:一次從輸入文件到共享內存區,另一個從共享內存區到輸出文件.實際上,進程之間在共享內存時,並不總是讀寫少量數據後就解除映射,有新的通信時,再重新建立共享內存區域.而是保持共享區域,知道通信完畢為止,這樣,數據內容就一直保存在共享內存中,並沒有寫回文件.共享內存中的內容往往是在解除映射時才寫回文件的.因此,采用共享內存的通信方式效率非常高.

linux從2.2內核開始就支持多種共享內存方式,如mmap系統調用,Posix共享內存,以及System V共享內存.本文主要介紹mmap系統調用的原理及應用.後續的文章會講解System V共享內存.

2.mmap系統調用

mmap系統調用是的是的進程間通過映射同一個普通文件實現共享內存.普通文件被映射到進程地址空間後,進程可以向像訪問普通內存一樣對文件進行訪問,不必再調用read,write等操作.與mmap系統調用配合使用的系統調用還有munmap,msync等.

實際上,mmap系統調用並不是完全為了用於共享內存而設計的.它本身提供了不同於一般對普通文件的訪問方式,是進程可以像讀寫內存一樣對普通文件操作.而Posix或System V的共享內存則是純粹用於共享內存的,當然mmap實現共享內存也是主要應用之一.

#include <sys/mman.h>
void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);

各個參數的說明如下:

  • start:映射區的開始地址,設置為0時表示由系統決定映射區的起始地址.
  • length:映射區的長度.長度單位是以內存頁為單位.
  • prot:期望的內存保護標志,不能與文件的打開模式沖突.是以下的某個值,可以通過or運算合理地組合在一起.
    • PROT_EXEC //頁內容可以被執行
    • PROT_READ //頁內容可以被讀取
    • PROT_WRITE //頁可以被寫入
    • PROT_NONE //頁不可訪問
  • flags:指定映射對象的類型,映射選項和映射頁是否可以共享.它的值可以是一個或者多個以下位的組合體.
    • MAP_FIXED //使用指定的映射起始地址,如果由start和len參數指定的內存區重疊於現存的映射空間,重疊部分將會被丟棄.如果指定的起始地址不可用,操作將會失敗.並且起始地址必須落在頁的邊界上.
    • MAP_SHARED //與其它所有映射這個對象的進程共享映射空間.對共享區的寫入,相當於輸出到文件.直到msync()或者munmap()被調用,文件實際上不會被更新.
    • MAP_PRIVATE //建立一個寫入時拷貝的私有映射.內存區域的寫入不會影響到原文件.這個標志和以上標志是互斥的,只能使用其中一個.
    • MAP_DENYWRITE //這個標志被忽略.
    • MAP_EXECUTABLE //同上
    • MAP_NORESERVE //不要為這個映射保留交換空間.當交換空間被保留,對映射區修改的可能會得到保證.當交換空間不被保留,同時內存不足,對映射區的修改會引起段違例信號.
    • MAP_LOCKED //鎖定映射區的頁面,從而防止頁面被交換出內存.
    • MAP_GROWSDOWN //用於堆棧,告訴內核VM系統,映射區可以向下擴展.
    • MAP_ANONYMOUS //匿名映射,映射區不與任何文件關聯.
    • MAP_ANON //MAP_ANONYMOUS的別稱,不再被使用.
    • MAP_FILE //兼容標志,被忽略.
    • MAP_32BIT //將映射區放在進程地址空間的低2GB,MAP_FIXED指定時會被忽略.當前這個標志只在x86-64平台上得到支持。
    • MAP_POPULATE //為文件映射通過預讀的方式准備好頁表.隨後對映射區的訪問不會被頁違例阻塞.
    • MAP_NONBLOCK //僅和MAP_POPULATE一起使用時才有意義.不執行預讀,只為已存在於內存中的頁面建立頁表入口.
  • fd:有效的文件描述詞.一般是由open()函數返回,其值也可以設置為-1,此時需要指定flags參數中的MAP_ANON,表明進行的是匿名映射.
  • offset:被映射對象內容的起點.一般設為0,表示從文件頭開始映射.

函數的返回值為最後文件映射到進程空間的地址,進程可以直接操作起始地址為該值的有效地址.系統調用mmap用於共享內存時有下面兩種常用的方式:

1)使用普通文件提供的內存映射:適用於任何進程之間.此時,需要打開或創建一個文件,然後再調用mmap,這種方式有許多特點和要注意的地方,我們在後面或舉例子說明.

2)使用特殊文件提東匿名內存映射:適用於具有親緣關系的進程之間.由於父子進程特殊的親緣關系,在父進程中吊牌用mmap,然後調用fork.那麼在調用fork之後,子進程急促繼承父進程匿名映射後的地址空間,同樣也繼承mmap返回的地址,這樣,父子進程就可以通過映射區進行通信了.注意,mmap返回的地址,需要由父進程共同維護.

對於任意的兩個進程可以使用第一種方式,而對於具有親緣關系的進程實現共享內存最好的方式應該是采用匿名內存映射的方式.此時,不必指定具體的文件,只要設定相應的標志即可,後面有相應的例子.

更多詳情請繼續閱讀第2頁的內容:http://www.linuxidc.com/Linux/2013-10/91443p2.htm

Copyright © Linux教程網 All Rights Reserved