Linux處理序間通訊共用記憶體

來源:互聯網
上載者:User

進程可以直接讀寫記憶體,不需要任何資料的複製。為了在多個進程間交換
資訊,核心專門留出一塊記憶體區,記憶體區可以由需要訪問的進程將其映射
到自己的私人地址空間,進程直接讀寫這一記憶體區,而不需要進行資料
的複製,提高了效率。由於多個進程共用記憶體,需要依靠同步機制如
互斥鎖和訊號量。

共用記憶體的實現分為三個步驟:

1. 建立共用記憶體,shmget()
shmget(建立或開啟共用記憶體)
表標頭檔 #include <sys/ipc.h>
#include <sys/shm.h>
函數定義   int shmget(key_t key, size_t size, int shmflg);
函數說明 key:IPC_PRIVATE或ftok的傳回值,標識的ID
       size:共用記憶體區大小。shmflg:同 open函數的許可權位,也可以用8進位標記法
傳回值:成功返回記憶體標識符,錯誤返回-1
#define IPC_CREAT01000
/* Create key if key does not exist. */
#define IPC_EXCL02000
/* Fail if key exists.  */
#define IPC_NOWAIT04000
/* Return error on wait.  */
2. 映射共用記憶體,把建立的共用記憶體映射到具體的進程空間,shmat()
shmat(映射共用記憶體)
表標頭檔 #include <sys/types.h>
      #include <sys/shm.h>
函數定義 void *shmat(int shmid, const void *shmaddr, int shmflg);

函數說明 shmid:要映射的共用記憶體區標識符
shmaddr:將共用記憶體映射到指定地址(若為NULL,則表示由系統自動完成映射)
shmflg:SHM_RDONLY:共用記憶體唯讀,預設為0,共用記憶體可讀寫
傳回值:成功映射後的地址,錯誤:-1
3. 撤銷映射shmdt()
shmdt(共用記憶體從進程中分離出來)
表標頭檔:  #include <sys/types.h>
         #include <sys/shm.h>
函數定義:  int shmdt(const void *shmaddr);
函數說明:shmaddr:共用記憶體後映射的地址
傳回值:成功0,錯誤-1
案例:建立一個共用記憶體區,之後建立子進程,在父子兩個進程中將共用記憶體
分別映射到各自的地址空間中
父進程先等待使用者輸入,然後使用者輸入的字串寫入到共用記憶體,之後往共用
記憶體的頭部寫入WROTE字串表示進程已成功寫入資料。子進程一直等到共用
記憶體的頭部字串為WROTE,然後將共用記憶體的有效資料(在父進程中使用者輸入的字串)
在螢幕上列印。父子兩個進程在工作之後,分別解除與共用記憶體的映射關係。
用標誌字串來實現父子之間的同步
命令ipcs,用於報告處理序間通訊機制狀態的命令,它可以查看共用記憶體,訊息佇列
等各種處理序間通訊機制的情況,用system()函數調用shell命令ipcs

sem_com.h-------------------------------------#ifndef __SEM_COM_H__#define__SEM_COM_H__/***訊號量相關的函數調用介面複雜,將它們封裝成二維單個*訊號量的幾個基本函數。*訊號量初始化函數init_sem()*P操作加一sem_p()*V操作減一sem_v()*從系統中刪除訊號量del_sem()*/#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>union semun {int val;};extern int init_sem(int sem_id, int init_value);extern int sem_p(int sem_id);extern int sem_v(int sem_id);extern int del_sem(int sem_id);#endif----------------------------------------------------sem_com.c-----------------------------------------------------#include "sem_com.h"/**訊號量初始化函數*/int init_sem(int sem_id, int init_value){union semun sem_union;sem_union.val = init_value; //init_value為初始值if (semctl(sem_id, 0, SETVAL, sem_union) == -1) {perror("Initialize semaphore");return -1;}return 0;}/**從系統中刪除訊號量的函數*/int del_sem(int sem_id){union semun sem_union;if (semctl(sem_id, 0, IPC_RMID, sem_union) == -1) {perror("Delete semaphore");return -1;}}/**P操作*/int sem_p(int sem_id){struct sembuf sem_b;sem_b.sem_num = 0;//單個訊號量的編號應該為0sem_b.sem_op = -1;//表示P操作sem_b.sem_flg = SEM_UNDO;//系統自動釋放將會在系統中殘留的訊號量if (semop(sem_id, &sem_b, 1) == -1) {perror("semop");return -1;}return 0;}/**V操作*/int sem_v(int sem_id){struct sembuf sem_b;sem_b.sem_num = 0;//單個訊號量的編號應該為0sem_b.sem_op = 1;//表示V操作sem_b.sem_flg = SEM_UNDO;if (semop(sem_id, &sem_b, 1) == -1) {perror("semop V");return -1;}return 0;}----------------------------------------------------shmem.c----------------------------------------------------#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>#include <sys/sem.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include "sem_com.h"#define BUFFER_SIZE 2048pid_t pid;int shmid;//要映射的共用記憶體區標識符int semid;//定義訊號量,用於實現共用記憶體的進程之間的互斥char *shm_addr;//共用記憶體映射到的地址char buff[BUFFER_SIZE];void function_init(){//建立一個訊號量semid = semget(ftok("/home",2), 1, 0666|IPC_CREAT);init_sem(semid, 1);//初始值為1//建立共用記憶體shmid = shmget(IPC_PRIVATE, BUFFER_SIZE, 0666);if (shmid < 0) {perror("shmget");exit(1);} else {printf("create shard-memory shmid: %d\n", shmid);}}void function_end(){//刪除訊號量del_sem(semid);//解除共用記憶體映射if ((shmdt(shm_addr)) < 0) {perror("shmdt");exit(1);} //刪除共用記憶體IPC_RMID刪除共用記憶體段if (shmctl(shmid, IPC_RMID, NULL) == -1) {perror("shmctl");exit(1);} else {printf("Delete shared-memory\n");}}int main(){function_init();pid = fork();if (pid == 0) {//子進程//映射共用記憶體shm_addr = shmat(shmid, NULL, 0);if (shm_addr == (void *)-1) {perror("Child: shmat");exit(1);} else{do{sem_p(semid);printf("\nChild:Attach shared-memory %p :%s \n", shm_addr, shm_addr);if (strncmp(shm_addr, "quit", 4) == 0) {break;}memset(shm_addr, 0, BUFFER_SIZE);sem_v(semid);} while(1);}//顯示共用記憶體情況//system("ipcs -m");} else if(pid > 0){//父進程//映射共用記憶體shm_addr = shmat(shmid, 0, 0);//父進程向共用記憶體定入資料do {sem_p(semid);//訊號值減一printf("Parent:Enter some text to the shared memory(enter 'quit' to exit):\n");if(fgets(buff, BUFFER_SIZE, stdin) == NULL) {perror("fgets");sem_v(semid);break;}strncpy(shm_addr, buff, strlen(buff));sem_v(semid);} while(strncmp(buff, "quit", 4) != 0);function_end();}exit(0);}--------------------------------------------------- shmem#./bts create shard-memory shmid: 1966089PARENTS:Enter some text to the shared memory(enter 'quit' to exit):hi child! "good afternoon"Child:Attach shared-memory 0xb78af000 :hi child! "good afternoon" PARENTS:Enter some text to the shared memory(enter 'quit' to exit):ok let's goChild:Attach shared-memory 0xb78af000 :ok let's go PARENTS:Enter some text to the shared memory(enter 'quit' to exit):quitDelete shared-memoryChild:Attach shared-memory 0xb78af000 :quit 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.