POSIX共享內存(內存映射)

本質:

兩個進程訪問同一個邏輯內存;

直接訪問內存,不用read()/write(),非常方便。

匿名映射文件:

設備	          作用	                      舉例
/dev/zero	永遠輸出0的設備文件	dd if=/dev/zero of=磁盤分區 count=1024 bs=1024
/dev/null	丟棄一切寫入其中數據	cat test > /dev/null
/dev/fd	       記錄用戶打開的文件描述符	ls /dev/fd/

頭文件:

sys/mman.h

鏈接庫:

rt

查看:

man shm_overview

ls  /dev/shm/

創建:

int shm_open(const char* name,int oflag,mode_t  mode);

name:

posix IPC名字。

oflag:

標誌:

標誌	     作用
O_CREAT	   沒有該對象則創建
O_EXCL	  如果O_CREAT指定,但name不存在,就返回錯誤
O_RDONLY	只讀
O_RDWR	        讀寫
O_WRONLY	只寫
O_TRUNC	    若存在則截斷

mode:

權限。

權限	作用
S_IWUSR	用戶/屬主寫
S_IRUSR	用戶/屬主讀
S_IWGRP	組成員寫
S_IRGRP	組成員讀
S_IWOTH	其他用戶寫
S_IROTH	其他用戶讀
返回值:

-1-------出錯

其他----共享內存描述符


刪除:

int shm_unlink(const char* name);

name:

posix IPC名字。

返回值:

-1——出錯

0——-成功

修改文件大小:

創建新文件時大小爲0,無法映射(存入數據)。

int  ftruncater(int fd,off_t length);

fd:

文件描述符。

length:

文件大小。

如果原文件大小比參數length大,超過部分刪除。

返回值:

0——成功

-1——失敗


建立內存映射:

void* mmap(void* start,size_t length,int prot,int flags,int fd,off_t offset);

start:

映射區的開始地址,一般爲NULL(從可移植考慮)。

如果寫NULL,就是讓系統決定映射區的起始地址。

length:

映射區的長度(以字節爲單位;不足一頁內存按一頁內存處理)。
port:

內存保護標誌。

不能與文件的打開模式衝突(打開爲讀->prot爲讀;打開爲讀寫->prot爲寫或讀寫)。

PROT_EXEC——頁內容可被執行

PROT_READ——頁內容可被讀寫

PROT_WRITE——頁可被寫

PROT_NONE——頁不可訪問

flags:

映射對象類型。

MAP_SHARED——變動共享

MAP_PRIVATE——變動私有

MAP_ANON———匿名內存映射(與MAP_SHARED一起用)

fd:

文件描述符(不能爲套接字和終端的fd)。

-1————匿名內存映射。

offset:

被映射對象內容的起點(偏移量)。

返回值:

MAP_FAILED——失敗

非MAP_FAILED——共享內存地址

刪除內存映射:

int munmap(void* start,size_t length);

start:

映射內存起始地址。

length:

內存大小。

返回值:

0——成功

-1——失敗

注意:

關閉mmap中的文件描述符不能刪除內存映射。

同步(類似fflush):

int msync(void* addr,size_t len,int flags);

addr:

映射內存起始地址。

len:

內存大小。

flags:

同步參數:

MS_ASYNC——異步;調用會立即返回。不等到更新的完成。

MS_SYNC——同步;調用會等到更新完成之後返回。

MS_INVALIDATE——通知使用該共享區域進程,數據以改變;在共享內容更改後,使得文件的其他映射失效。

返回值:

0——成功

-1——失敗

代碼:

創建+修改文件大小:

#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>

int main(int argc,char* argv[]){
	int fd = shm_open(argv[1],O_CREAT|O_RDWR,0644);
	ftruncate(fd,atoi(argv[2]));
	void* buf = NULL;
	if(( buf =  mmap(NULL,BUFSIZ,PROT_WRITE,MAP_SHARED,fd,0)) == MAP_FAILED){
		perror("mmap error\n");
		return 1;
	}
}

刪除:

#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>

int main(int argc,char* argv[]){
	shm_unlink(argv[1]);
}

讀:

#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>

int main(int argc,char* argv[]){
	int fd = shm_open(argv[1],O_RDONLY,0);
	void* buf = NULL;
	if(( buf =  mmap(NULL,BUFSIZ,PROT_READ,MAP_SHARED,fd,0)) == MAP_FAILED){
		perror("mmap error\n");
		return 1;
	}
	printf("%s\n",buf);
	munmap(buf,BUFSIZ);
}

寫:

#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>

int main(int argc,char* argv[]){
	int fd = shm_open(argv[1],O_RDWR,0);
	void* buf = NULL;
	if(( buf =  mmap(NULL,BUFSIZ,PROT_WRITE,MAP_SHARED,fd,0)) == MAP_FAILED){
		perror("mmap error\n");
		return 1;
	}
	strcpy(buf,argv[2]);
	munmap(buf,BUFSIZ);
}

親緣進程間的匿名映射:

#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>

int main(int argc,char* argv[]){
	void* buf = NULL;
	if(( buf =  mmap(NULL,BUFSIZ,PROT_WRITE|PROT_READ,MAP_SHARED|MAP_ANON,-1,0)) == MAP_FAILED){
		perror("mmap error\n");
		return 1;
	}
	if(fork()){
		strcpy(buf,argv[1]);	
	}else{
		printf("%s\n",buf);
	}
	munmap(buf,BUFSIZ);
}


發佈了93 篇原創文章 · 獲贊 44 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章