程序間通訊——mmap()函式
mmap可以把磁碟檔案的一部分直接對映到記憶體,這樣檔案中的位置直接就有對應的記憶體地址,對檔案的讀寫可以直接使用指標來做,而不需要read/write函式。
void *mmap(void *addr,size_t length,int port,int flgs,int fd,off_t offset);
int munmap(void *addr,size_t length);
如果addr引數為NULL,核心會自己在程序地址空間中選擇合適的地址建立對映。如果addr不是NULL,則給核心一個提示,應該從什麼地方開始對映,核心會選擇addr之上的某個合適的地址開始對映。建立對映之後,真正的首地址通過返回值得到。length引數是需要對映的那一部分檔案的長度。offset引數是從檔案的什麼位置開始對映,必須是頁大小的整數倍(32位通常是4K)。fd引數表示檔案描述符。 port引數的取值有一以下四種:
a、PORT_EXEC:表示對映的這一段可執行;
b、PORT_READ:表示對映的這一段可讀;
c、PORT_WRITE:表示對映的這一段可寫;
d、PORT_NONE:表示對映的這一段不可訪問。
flgs引數的取值有很多種,目前只需要瞭解兩種即可:
MAP_SHARED:多個程序對同一個檔案時共享的,一個程序對對映的記憶體做了修改,另一個程序也會看到這種變化。
MAP_PRIVATE:多個程序對同一個檔案的對映是不共享的,一個程序對對映的記憶體做了修改,另一個程序並不會看到這種變化,也不會真的寫到檔案中。
mmap如果成功則返回對映的首地址,如果出錯則返回常數MAP_FAILED((void *)-1)。當程序終止時,該程序的對映會自動解除,也可以呼叫munmap解除對映。成功返回0,出錯返回-1。
應用舉例:和上篇介紹共享記憶體時的實現功能一樣,下面看程式碼:
讀檔案
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <error.h>
int main(int argc, char **argv)
{
int fd;
char *mapped;
/* 開啟檔案 */
if ((fd = open(argv[1 ], O_RDWR)) < 0) {
perror("open");
}
/* 將檔案對映至程序的地址空間 */
if ((mapped = (char *)mmap(NULL, 1024, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED {
perror("mmap");
}
/* 檔案已在記憶體, 關閉檔案也可以操縱記憶體 */
close(fd);
/* 每隔兩秒檢視儲存對映區是否被修改 */
while (1) {
printf("%s\n", mapped);
sleep(2);
}
return 0;
}
寫檔案
#include <stdio.h>
#include <error.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <error.h>
int main(int argc, char **argv)
{
int fd, i = 0;
char *mapped;
/* 開啟檔案 */
if ((fd = open(argv[1], O_RDWR,0644)) < 0) {
perror("open");
}
/* 共享檔案對映將無法修改檔案 */
if ((mapped = (char *)mmap(NULL,1024, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) {
perror("mmap");
}
/* 對映完後, 關閉檔案也可以操縱記憶體 */
close(fd);
/* 修改一個字元 */
while(1){
mapped[i++] = '#';
mapped[i] = '\0';
sleep(1);
}
return 0;
}