Linux基礎——內存共享映射(mmap函數的使用)

進程間的通信就像兩人的交流,需要一個“公共場所”常見的有1、內核 2、內存 3、磁盤。

mmap

  • 用途:進程間的通信
  • 使用原理:把磁盤的一個空間映射到內存中,如下圖所示
  • 函數:void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
  • 參數解析
    • 參數1:希望在內存的哪個位置(即內存地址),傳NULL,由系統自動找一塊內存空間。一般都寫NULL
    • 參數2:請內存長度(可以使用lseek函數來測試文件大小)
    • 參數3:prot頁面屬性(映射到內存的這一段的權限)

    • 參數4:狀態標誌,有兩種:共享映射MAP_SHARED 和 私有映射MAP_PRIVATE
      • 共享映射MAP_SHARED:多個進程對同一個文件的映射是共享的,一個進程對映射的內存做了修改,另一個進程也會看到這種變化。 (即,我這個進程修改了一個地方,其他進程也看得到)
      • 私有映射MAP_PRIVATE:多個進程對同一個文件的映射不是共享的,一個進程對映射的內存做了修改,另一個進程並不會看到這種變化,也不會真的寫到文件中去。
    • 參數5:文件操作符
  • 返回值:如果mmap成功則返回映射首地址,如果出錯則返回常數MAP_FAILED

mmap的注意事項:

1、用於進程之間通信,一般設計成結構體,用於傳輸數據

2、進程間通信,一般設計成臨時文件(讀完刪除使用unlink)

3、當有總線出錯,優先查看共享文件是否有存儲空間

4、如果段出錯可能是使用到了,還沒創建的文件(或者是不存在的文件)

示例文件

寫文件端

#include<sys/types.h>
#include<sys/stat.h> 
#include<unistd.h>
#include<fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#define MAPLEN 0x1000	//這個我來定義文件的大小,一會要映射到內存

//定義一個學生的結構體
struct STU 
{
	int ID;
	char name[64];
	char sex;
};

//定義一個函數,專門來輸出進程執行時的錯誤
void sys_err(char *str,int exitno)
{
	perror(str);
	exit(exitno);
}

/*
你要先要創建一個hello文件,不然一會執行的時候會報段出錯
使用mmap來修改文件信息
*/

//文件寫成傳參的形式
int main(int argc,char *argv[])
{
	//創建一個文件結構體變量
	struct STU *mm;
	int fd,i=0;

 	if(argc < 2)
	{
		printf("enter your name\n");
		exit(1);
	}
	
	//執行時輸入的文件名,會在這裏打開
	fd = open(argv[1],O_RDWR|O_CREAT,0777);
 	
 	//如果打開失敗
	if(fd<0)
	{
		//報錯
		sys_err("open",1);
	}
	
	//寫入一個“\0”,來擴展文件,讓文件由存儲空間,不寫這下面兩個if會報總線錯誤
	if(lseek(fd,MAPLEN-1,SEEK_SET)<0)
	{
		sys_err("mmsp",3);
	}
	if(write(fd,"\0",1)<0)
	{
		sys_err("write",4);
	}
	//
	mm = mmap(NULL,MAPLEN,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
	
	if(mm == MAP_FAILED)
	{
		sys_err("mmsp",2);
	}
	close(fd);
	
	while(1)
	{
		mm->ID = i;	
 		sprintf(mm->name,"zhaozhao - %d",i++);
		 if(i%2 == 0)
	 	{
	 		mm->sex = 'm';
	 	}
	 	else
	 	{
	 		mm->sex = 'w';
	 	}
	 	sleep(1);
	}
	
	//關閉映射
	munmap(mm,MAPLEN);
	 
	
	return 0;

讀文件端

#include<sys/types.h>
#include<sys/stat.h> 
#include<unistd.h>
#include<fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#define MAPLEN 0x1000
struct STU 
{
	int ID;
	char name[64];	
	char sex;
};

void sys_err(char *str,int exitno)
{
	perror(str);
	exit(exitno);
}


int main(int argc,char *argv[])
{
	struct STU *mm;
	int fd,i=0;
 
	if(argc < 2)
	{
	printf("enter your name\n");
	exit(1);
 	}
 	
 	//打開文件,只讀模式
 	fd = open(argv[1],O_RDWR);
 
 	if(fd < 0)
 	{
  		sys_err("open",1);
 	}

	mm = mmap(NULL,MAPLEN,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
 
 	if(mm == MAP_FAILED)
 	{
  		sys_err("mmsp",2);
 	}
 	close(fd);
	
	//讀完刪除文件,防止創建多個文件
 	nulink(argv[1]);
	while(1)
 	{
  		printf("%d\n",mm->ID);
  		printf("%s\n",mm->name);
  		printf("%c\n",mm->sex);
  		sleep(1);
 	}
	//關閉
 	munmap(mm,MAPLEN); 
 	return 0;
}

在寫端執行文件的的時候,輸入文件名稱(沒有創建過的文件),在執行讀端的時候輸入參數(前面創建的文件名稱)這樣在終端上就能看見讀取的數據。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章