Linux處理序間通訊(IPC)編程實踐(八)共用記憶體的使用-POSIX 共用記憶體(API)

來源:互聯網
上載者:User

Linux處理序間通訊(IPC)編程實踐(八)共用記憶體的使用-POSIX 共用記憶體(API)

1、Posix提供了兩種在無親緣關係進程間共用記憶體區的方法:

(1)記憶體對應檔:先有open函數開啟,然後調用mmap函數把得到的描述符映射到當前進程地址空間中的一個檔案(上一篇博文所用到的就是)。

(2)共用記憶體區對象:先有shm_open開啟一個Posix IPC名字(也可以是檔案系統中的一個路徑名),然後調用mmap將返回的描述符映射到當前進程的地址空間。這兩種方法都需要調用mmap,差別在於作為mmap的參數之一的描述符的擷取手段。

2、Posix共用記憶體區對象

 Posix共用記憶體區涉及以下兩個步驟要求:

(1)指定一個名字參數調用shm_open,以建立一個新的共用記憶體區對象或開啟一個已經存在的共用記憶體區對象。

(2)調用mmap把這個共用記憶體區映射到調用進程的地址空間。

注意:mmap用於把一個記憶體區對象映射到調用進程地址空間的是該對象的一個已經開啟描述符。

關於Posix共用記憶體區對象的API如下:

 

#include #include        /* For mode constants */#include              /* For O_* constants */int shm_open(const char *name, int oflag, mode_t mode);int shm_unlink(const char *name);        int ftruncate(int fd, off_t length);int fstat(int fd, struct stat *buf);

1. 建立/擷取一個共用記憶體

 

 

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

 

參數:

name: 共用記憶體名字;

oflag: 與open函數類型, 可以是O_RDONLY, O_WRONLY, O_RDWR, 還可以按位或上O_CREAT, O_EXCL, O_TRUNC.

mode: 此參數總是需要設定, 如果oflag沒有指定O_CREAT, 則mode可以設定為0;

傳回值:

成功: 返回一個檔案描述符;

失敗: 返回-1;

注意-Posix IPC名字限制:

1. 必須以”/”開頭, 並且後面不能還有”/”, 形如:/file-name;

2. 名字長度不能超過NAME_MAX

3. 連結時:Link with -lrt.

/** 樣本: 共用記憶體的開啟與關閉 **/  int main(int argc,char *argv[])  {      int shmid = shm_open("/xyz", O_RDWR|O_CREAT, 0666);      if (shmid == -1)          err_exit("shmget error");        cout << "share memory open success" << endl;      close(shmid);  }  
2. 修改共用記憶體大小

 

int ftruncate(int fd, off_t length); 
該函數不僅可用於修改共用記憶體大小, 而且可以用於修改檔案大小
/** 樣本: 修改共用記憶體大小 將其修改為一個Student結構體的大小 **/  struct Student  {      char name[32];      int age;  };  int main(int argc,char *argv[])  {      int shmid = shm_open("/xyz", O_RDWR|O_CREAT, 0666);      if (shmid == -1)          err_exit("shmget error");      if (ftruncate(shmid, sizeof(Student)) == -1)          err_exit("ftruncate error");        cout << "share memory change size success" << endl;      close(shmid);  }  
3. 擷取共用記憶體狀態
int fstat(int fd, struct stat *buf);  
該函數不僅可用於擷取共用記憶體狀態, 而且可以用於擷取檔案狀態, 與前面曾經講述過的stat, lstat類型;
//stat結構體  struct stat  {      dev_t     st_dev;     /* ID of device containing file */      ino_t     st_ino;     /* inode number */      mode_t    st_mode;    /* protection */      nlink_t   st_nlink;   /* number of hard links */      uid_t     st_uid;     /* user ID of owner */      gid_t     st_gid;     /* group ID of owner */      dev_t     st_rdev;    /* device ID (if special file) */      off_t     st_size;    /* total size, in bytes */      blksize_t st_blksize; /* blocksize for filesystem I/O */      blkcnt_t  st_blocks;  /* number of 512B blocks allocated */      time_t    st_atime;   /* time of last access */      time_t    st_mtime;   /* time of last modification */      time_t    st_ctime;   /* time of last status change */  };  
/** 樣本: 擷取共用記憶體的mode和size **/  int main(int argc,char *argv[])  {      int shmid = shm_open("/xyz", O_RDWR|O_CREAT, 0666);      if (shmid == -1)          err_exit("shmget error");      if (ftruncate(shmid, sizeof(Student)) == -1)          err_exit("ftruncate error");        struct stat buf;      if (fstat(shmid, &buf) == -1)          err_exit("lstat error");      // 注意: 擷取許可權時, 需要&上0777, 而且要以%o, 八進位方式列印      printf("mode: %o\n", buf.st_mode&0777);      printf("size: %ld\n", buf.st_size);        close(shmid);  }  
4. 刪除一個共用記憶體對象
int main(int argc,char *argv[])  {      shm_unlink("/xyz");  }  
5. 共用記憶體的映射/卸載
#include   void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);  int munmap(void *addr, size_t length);  

 

參數:

addr: 要映射的起始地址, 通常指定為NULL, 讓核心自動選擇;

length: 映射到進程地址空間的位元組數, 通常是先前已經建立的共用記憶體的大小;

prot: 映射區保護方式(見下);

flags: 標誌(通常指定為MAP_SHARED, 用於處理序間通訊);

fd: 檔案描述符(填為shm_open返回的共用記憶體ID);

offset: 從檔案頭開始的位移量(一般填為0);

 

prot

說明

PROT_READ

頁面可讀

PROT_WRITE

頁面可寫

PROC_EXEC

頁面可執行

PROC_NONE

頁面不可訪問

 

flags

說明

MAP_SHARED

變動是共用的

MAP_PRIVATE

變動是私人的

MAP_FIXED

準確解釋addr參數, 如果不指定該參數, 則會以4K大小的記憶體進行對齊

MAP_ANONYMOUS

建立匿名映射區, 不涉及檔案

 

mmap傳回值:

成功: 返回映射到的記憶體區的起始地址;

失敗: 返回MAP_FAILED;

注意:mmap失敗返回EACCES錯誤的原因:

EACCES A file descriptor refers to a non-regular file.

Or MAP_PRIVATE was requested, but fd is not open for reading.

Or MAP_SHARED was requested and PROT_WRITE is set, but fd is not open

in read/write (O_RDWR) mode. Or PROT_WRITE is set, but the file is append-only.

/** 樣本: 向共用記憶體寫入資料 **/  int main(int argc,char *argv[])  {      int shmid = shm_open("/xyz", O_RDWR, 0);      if (shmid == -1)          err_exit("shm_open error");        struct stat buf;      if (fstat(shmid, &buf) == -1)          err_exit("fstat error");      Student *p = (Student *)mmap(NULL, buf.st_size,                                   PROT_WRITE, MAP_SHARED, shmid, 0);      if (p == MAP_FAILED)          err_exit("mmap error");      strcpy(p->name, "Hadoop");      p->age = 5;        munmap(p, buf.st_size);      close(shmid);  }  

 

/** 從共用記憶體讀出資料 **/  int main(int argc,char *argv[])  {      int shmid = shm_open("/xyz", O_RDONLY, 0);      if (shmid == -1)          err_exit("shm_open error");        struct stat buf;      if (fstat(shmid, &buf) == -1)          err_exit("fstat error");      Student *p = (Student *)mmap(NULL, buf.st_size,                                   PROT_READ, MAP_SHARED, shmid, 0);      if (p == MAP_FAILED)          err_exit("mmap error");        cout << "name: " << p->name << ", age: " << p->age << endl;        munmap(p, buf.st_size);      close(shmid);  }  

[注]

-Posix共用記憶體預設建立在/dev/shm目錄下

-可以使用od命令查看共用記憶體的內容

od -c /dev/shm/xyz







 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.