1. 程式人生 > >程序間通訊——mmap()函式

程序間通訊——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;  
}