LINUX 中的mmap淺析
原創LINUX系統程式設計水平有限,參考UNIX系統程式設計手冊
LINUX 中的mmap淺析
一、mmap基本原理和分類
在LINUX中我們可以使用mmap用來在程式虛擬地址空間中分配建立一片虛擬記憶體地址對映
其可以是
1、檔案對映
使用檔案內容初始化記憶體
2、匿名對映
初始化全為0的記憶體空間(calloc也可以)
下面配圖來自UNIX系統程式設計手冊
而對於是否共享又分為
1、私有對映(MAP_PRIVATE)
多程式間資料共享,修改不反應到磁碟實際檔案,
私有寫時複製實現
2、共享對映(MAP_SHARED)
多程式間資料共享,修改反應到磁碟實際檔案中。
那麼總結起來有4種組合
1、私有檔案對映
多個程式使用同樣的實體記憶體頁進行初始化,但是各個程式
對記憶體檔案的修改不會共享,也不會反應到物理檔案中,比如
我們LINUX .so動態庫檔案就採用這種方式對映到各個程式虛擬
地址空間中
2、私有匿名對映
mmap會建立一個新的對映,各個程式不共享,這種使用主要用於
分配記憶體(malloc分配大記憶體會呼叫mmap)。
3、共享檔案對映
多個程式透過虛擬記憶體技術共享同樣的實體記憶體空間,對記憶體檔案
的修改會反應到實際物理檔案中,他也是程式間通訊(IPC)的一種機制
4、共享匿名對映
這種機制在進行fork的時候不會採用寫時複製,父子程式完全共享
同樣的實體記憶體頁,這也就實現了父子程式通訊(IPC).
下面也是UNIX系統程式設計手冊截圖
在/proc/PID/maps下我們可以找到一個當前程式使用mmap建立的對映比如:
379a000000-379a016000 r-xp 00000000 08:03 12320771 /lib64/libgcc_s-4.4.7-20120601.so.1
379a016000-379a215000 ---p 00016000 08:03 12320771 /lib64/libgcc_s-4.4.7-20120601.so.1
379a215000-379a216000 rw-p 00015000 08:03 12320771 /lib64/libgcc_s-4.4.7-20120601.so.1
379a400000-379a4e8000 r-xp 00000000 08:03 9700201 /usr/lib64/libstdc++.so.6.0.13
379a4e8000-379a6e8000 ---p 000e8000 08:03 9700201 /usr/lib64/libstdc++.so.6.0.13
379a6e8000-379a6ef000 r--p 000e8000 08:03 9700201 /usr/lib64/libstdc++.so.6.0.13
379a6ef000-379a6f1000 rw-p 000ef000 08:03 9700201 /usr/lib64/libstdc++.so.6.0.13
對於解釋可以參考UNIX系統程式設計手冊如下描述
二、mmap函式原型
void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
引數有點多
addr:對映放到哪裡(虛擬地址),一般傳NULL,讓核心自己決定
length:對映的大小(直接),最小是系統頁的整數倍(4K)
port:點陣圖掩碼
PROT_NONE 不能訪問
PROT_READ 可讀取
PROT_WRITE 可修改
PROT_EXEC 可執行
非法訪問或報SIGSEGV段錯誤訊號
flags:點陣圖掩碼
MAP_ANONYMOUS:建立一個匿名對映
MAP_PRIVATE:私有對映
MAP_SHARED:共享對映(注意並不能保證一定實際寫入物理磁碟(MSYNC))
MAP_FIXED:addr必須是頁對齊地址
其他標示不做解釋
fd:對映檔案的檔案描述符
offset:從檔案的哪個位置開始對映,必須是系統頁的整數倍(4K)
返回值:
成功返回對映的虛擬記憶體地址的起始地址,失敗返回MAP_FAILED
三、建立匿名對映
1、指標MAP_ANONYMOUS,並且fd指定為0
2、開啟/dev/zero檔案將檔案描述符傳遞給mmap()
匿名對映會分配初始化全為0的虛擬記憶體空間
四、其他函式
int msync(void *addr, size_t length, int flags);
用於將kener buffer的資料同步到磁碟
int munmap(void *addr, size_t length);
用於解除對映
五、程式例項
下面我們透過mmap做私有匿名對映來完成一個小的執行緒間同步問題程式,用這片
記憶體區域來做執行緒間通訊
點選(此處)摺疊或開啟
-
#include<iostream>
-
#include<sys/mman.h>
-
#include<pthread.h>
-
#include<string.h>
-
#define uint unsigned int
-
#define MMSIZE (uint)(1<<23)
-
#define MSIZE (uint)(1<<20)
-
#define MPRT (uint)(1<<16)
-
using namespace std;
-
-
-
-
class tc
-
{
-
private:
-
uint a;
-
public:
-
tc():a(1)
-
{
-
;
-
}
-
~tc()
-
{
-
;
-
}
-
void add()
-
{
-
a=a+1;
-
}
-
void set()
-
{
-
a=1;
-
}
-
void prt(int i)
-
{
-
if(!(i%(MPRT)))
-
{
-
cout<<":"<<a;
-
}
-
}
-
-
};
-
-
struct tt
-
{
-
tc* p1;
-
pthread_mutex_t* p2;
-
};
-
-
void* test(void* arg)
-
{
-
int i = 0;
-
tt* s = NULL;
-
s = (tt*)arg;
-
int maxloop = 50;
-
while(maxloop--)
-
{
-
i = MSIZE;
-
pthread_mutex_lock(s->p2);//MUTEX保護臨界區
-
cout<<"Thread:"<<pthread_self()<<" work now!!!\n";
-
for(;i--;)
-
{
-
(s->p1+i)->prt(i);
-
(s->p1+i)->add();
-
}
-
cout<<"\n";
-
pthread_mutex_unlock(s->p2);//解鎖
-
}
-
}
-
-
-
-
int main(void)
-
{
-
pthread_t tid[3];
-
pthread_mutex_t pmut;
-
tt s1;
-
tc* p = (tc*)mmap(NULL,MMSIZE,PROT_READ|PROT_WRITE,MAP_ANONYMOUS|MAP_PRIVATE,-1,0);//MMAP分配一個匿名私有虛擬記憶體用於執行緒間通訊
-
pthread_mutex_init(&pmut,NULL);
-
s1.p1 = p;
-
s1.p2 = &pmut;
-
-
int i = MSIZE+1;
-
-
for(;i--;)
-
{
-
(p+i)->set();//初始化所有的a=1
-
}
-
-
-
for(i=0;i<3;i++)
-
{
-
pthread_create(tid+i,NULL,test,(void*)&s1);//建立3個執行緒
-
}
-
-
for(i = 0;i<3;i++)
-
{
-
pthread_join( *(tid+i) , NULL);//堵塞回收執行緒
-
}
-
pthread_mutex_destroy(&pmut);
-
munmap(p,MMSIZE);
-
- }
我們使用MUTEX保護臨界區這個數數還是正常進行。最後正常數到了150
Thread:140545405572864 work now!!!
:32:32:32:32:32:32:32:32:32:32:32:32:32:32:32:32
Thread:140545397180160 work now!!! (執行緒140545405572864 失去CPU執行緒140545397180160執行)
:33:33:33:33:33:33:33:33:33:33:33:33:33:33:33:33
..................
Thread:140545397180160 work now!!!
:58:58:58:58:58:58:58:58:58:58:58:58:58:58:58:58
Thread:140545405572864 work now!!!(執行緒140545405572864重新獲得CPU)
:59:59:59:59:59:59:59:59:59:59:59:59:59:59:59:59
............
Thread:140545388787456 work now!!!
:150:150:150:150:150:150:150:150:150:150:150:150:150:150:150:150
作者微信:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/7728585/viewspace-2142411/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Android中mmap原理及應用簡析Android
- Linux 中斷處理淺析Linux
- 淺析Linux的軟中斷的實現Linux
- 淺析Linux中的零拷貝技術Linux
- Java網路程式設計與NIO詳解8:淺析mmap和Direct BufferJava程式設計
- 淺析java中的IO流Java
- 淺析 JS 中的 Event LoopJSOOP
- 淺析linux容器--DockerLinuxDocker
- 淺析nodejs中的stream(流)NodeJS
- 淺析js中的Object.create()JSObject
- java中的JAR檔案淺析JavaJAR
- angular中的概念和原理淺析Angular
- 淺析vue中的元件通訊Vue元件
- java中的反射機制淺析Java反射
- Linux 程式排程淺析Linux
- Linux 組排程淺析Linux
- Linux 程式狀態淺析Linux
- Linux 執行緒淺析Linux執行緒
- Linux安裝淺析(轉)Linux
- redux中間鍵淺析Redux
- 淺析Linux中伺服器程式碼部署篇(分享)Linux伺服器
- 淺析Java中的執行緒池Java執行緒
- Linux系統——架構淺析Linux架構
- linux slub分配器淺析Linux
- Netty 中的記憶體分配淺析Netty記憶體
- 淺析 Vue 2.6 中的 nextTick 方法Vue
- 淺析Java併發中的單例模式Java單例模式
- 淺析php中的異常與錯誤PHP
- 淺析MySQL事務中的redo與undoMySql
- 淺析c++11中的“=default“和“=delete“C++delete
- .NET6中的await原理淺析AI
- Java 集合中的排序演算法淺析Java排序演算法
- 淺析tornado 中demo的 blog模組
- 淺析Android中的訊息機制Android
- 淺析C#中的等號“==”和EqualsC#
- Linux零複製技術淺析Linux
- Linux系統呼叫機制淺析Linux
- Linux 核心SMP負載均衡淺析Linux負載