存儲(chǔ)映射I/O 介紹
????存儲(chǔ)映射IO(Memory-mapped I/O) 使用一個(gè)磁盤文件與存儲(chǔ)空間的一個(gè)緩沖區(qū)相映射。于是當(dāng)緩沖區(qū)中取出數(shù)據(jù)篮奄,就相當(dāng)于讀文件中的相應(yīng)字節(jié)捆愁。于此類似。間數(shù)據(jù)存入緩沖區(qū)窟却,則相應(yīng)的字節(jié)就會(huì)自動(dòng)寫入文件昼丑。因?yàn)閿?shù)據(jù)已經(jīng)寫入文件,即使機(jī)器重啟數(shù)據(jù)還在夸赫。
mmap函數(shù)
????使用這種方法菩帝,首先應(yīng)通知內(nèi)核,間一個(gè)指定文件映射到存儲(chǔ)區(qū)域中茬腿⌒哺剑可以通過mmap函數(shù)來實(shí)現(xiàn)。
函數(shù)原型 :
void *mmap(void *adrr, size_t length, int prot, int flags, int fd, off_t offset);
參數(shù):
addr:建立映射區(qū)的首地址滓彰,有Linux內(nèi)核指定控妻。使用時(shí)傳NULL即可
length:與創(chuàng)建映射取的大小
prot: 映射區(qū)權(quán)限PROT_READ、PROT_WRITE揭绑、PROT_READ|PROT_WRITE
flags:標(biāo)志位參數(shù)(常用于設(shè)定更新物理區(qū)域弓候、設(shè)置共享、創(chuàng)建匿名映射區(qū))
MAP_SHARED: 會(huì)將映射區(qū)所做的操作反映到物理設(shè)備(磁盤)上他匪。
MAP_PRIVATE: 映射區(qū)所做的修改不會(huì)反映到物理設(shè)備菇存。
fd: 用來建立映射區(qū)的文件描述符
offset: 映射文件的偏移(4k的整數(shù)倍)
munmap函數(shù)
當(dāng)不需要這個(gè)映射內(nèi)存時(shí)通過munmap函數(shù)來釋放
函數(shù)原型:
int munmap(void *addr, size_t length);
參數(shù):
addr :mmap的返回值
length:釋放區(qū)域的長度
示例代碼
mem.txt文件
jjjjjjjj
mmap.c文件
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <string.h>
int main()
{
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <string.h>
int main()
{
int fd = open("mem.txt",O_RDWR);//創(chuàng)建并且截?cái)辔募? //int fd = open("mem.txt",O_RDWR|O_CREAT|O_TRUNC,0664);//創(chuàng)建并且截?cái)辔募?
//創(chuàng)建映射區(qū)
char *mem = mmap(NULL,20,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
//char *mem = mmap(NULL,8,PROT_READ|PROT_WRITE,MAP_PRIVATE,fd,0);
if(mem == MAP_FAILED){
perror("mmap err");
return -1;
}
//拷貝數(shù)據(jù)
strcpy(mem,"helloworld");
// mem++;
//釋放mmap
if(munmap(mem,20) < 0){
perror("munmap err");
}
close(fd);
return 0;
}
運(yùn)行代碼之后,發(fā)現(xiàn)mem.txt文件內(nèi)容已經(jīng)改變
[root@VM_0_11_centos linux]# cat mem.txt
helloworl[root@VM_0_11_centos linux]#
**讀寫例 **
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/wait.h>
typedef struct _Student{
int sid;
char sname[20];
}Student;
int main(int argc,char *argv[])
{
//open file
int fd = open(argv[1],O_RDWR);
//mmap
int length = sizeof(Student);
Student *stu = mmap(NULL,length,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
if(stu == MAP_FAILED){
perror("mmap err");
return -1;
}
//read data
while(1){
printf("sid=%d,sname=%s\n",stu->sid,stu->sname);
sleep(1);
}
//close and munmap
munmap(stu,length);
close(fd);
return 0;
}
寫示例
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/wait.h>
typedef struct _Student{
int sid;
char sname[20];
}Student;
int main(int argc,char *argv[])
{
if(argc != 2){
printf("./a.out filename\n");
return -1;
}
// 1. open file
int fd = open(argv[1],O_RDWR|O_CREAT|O_TRUNC,0666);
int length = sizeof(Student);
ftruncate(fd,length);
// 2. mmap
Student * stu = mmap(NULL,length,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
if(stu == MAP_FAILED){
perror("mmap err");
return -1;
}
int num = 1;
// 3. 修改內(nèi)存數(shù)據(jù)
while(1){
stu->sid = num;
sprintf(stu->sname,"xiaoming-%03d",num++);
sleep(1);//相當(dāng)于沒隔1s修改一次映射區(qū)的內(nèi)容
}
// 4. 釋放映射區(qū)和關(guān)閉文件描述符
munmap(stu,length);
close(fd);
return 0;
}
map的一些問題
1.如果對(duì)mem越界操作會(huì)怎樣邦蜜?
多出的數(shù)據(jù)會(huì)丟失依鸥,盡量避免這樣的操作
2.如果文件描述符向關(guān)閉,對(duì)mmap映射有沒有影響
沒有影響
3.open的時(shí)候悼沈,可以新創(chuàng)建一個(gè)文件來創(chuàng)建映射區(qū)嗎贱迟?
不可以姐扮,使用的文件大小不能為0
4.如果文件偏移隨便填一個(gè)數(shù)會(huì)怎么樣?
運(yùn)行時(shí)會(huì)報(bào)錯(cuò)
匿名映射
???? 通過使用我們發(fā)現(xiàn)衣吠,使用映射區(qū)來完成文件讀寫十分方便茶敏,賦值進(jìn)程通信也比較容易。但是缺陷是缚俏,每次創(chuàng)建映射區(qū)一定要依賴一個(gè)文件才能實(shí)現(xiàn)惊搏。通常為了建立映射區(qū)要open一個(gè)temp文件,創(chuàng)建好了再unlink,close掉忧换,比較麻煩恬惯。可以直接使用匿名映射來代替亚茬。Linux系統(tǒng)給我們提供了創(chuàng)建匿名映射區(qū)的方法酪耳,無需依賴一個(gè)文件,即可創(chuàng)建映射取才写。同樣需要借助標(biāo)志位參數(shù)flags來指定葡兑。
示例代碼:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/wait.h>
int main()
{
//修改創(chuàng)建的參數(shù)
int *mem = mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANON,-1,0);
if(mem == MAP_FAILED){
perror("mmap err");
return -1;
}
...