Linux 進程間的通信(二)—共享內存通信
共享內存通信簡介
共享內存可以說是最有用的進程間通信方式,也是最快的IPC形式。兩個不同進程A、B共享內存的意思是,同一塊物理內存被映射到進程A、B各自的進程地址空間。進程A可以即時看到進程B對共享內存中數據的更新,反之亦然。由於多個
進程共享
同一塊內存區域,必然需要某種同步機制
,互斥鎖
和信號量
都可以.
主要有以下幾個API:shmget()、shmat()、shmdt()及shmctl()。
shmget()用來獲得共享內存區域的ID,如果不存在指定的共享區域就創建相應的區域。
shmat()把共享內存區域映射到調用進程的地址空間中去,這樣,進程就可以方便地對共享區域進行訪問操作。
shmdt()調用用來解除進程對共享內存區域的映射。Shmctl()實現對共享內存區域的控制操作。
shmget函數
shmget函數的作用是在內存中獲得一段共享內存區域。shmget函數原型如下:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key,int size,int shmflg)
函數返回值:該系統調用成功則返回共享內存段標識符ID,即shmid;若出錯則返回-1。
函數傳入參數key爲IPC結構的鍵值,通常取常量IPC_PRIVATE;參數size爲該共享內存區大小,如果創建一個新的區域,必須指定其size參數。如果引用一個已有的區域,則size應該爲0;
參數shmflg:
0:取共享內存標識符,若不存在則函數會報錯
IPC_CREAT:當shmflg&IPC_CREAT爲真時,如果內核中不存在鍵值與key相等的共享內存,則新建一個共享內存;如果存在這樣的共享內存,返回此共享內存的標識符
IPC_CREAT|IPC_EXCL:如果內核中不存在鍵值與key相等的共享內存,則新建一個共享內存;如果存在這樣的共享內存則報錯
shmat函數
映射共享內存,使用函數shmat,它的作用是創建的共享內存映射到具體的進程空間去。shmat函數原型如下:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
char *shmat(int shmid,const void *shmaddr,int shmflg)
函數傳入參數shmid爲通過shmget得到的共享內存區標識符ID;參數shmaddr表示 將共享內存映射到指定位置,若爲0則表示把該段共享內存映射到調用進程的地址空間,推薦採用這個參數;參數shmflg爲選項位用來設置權限,常用的選項是SHM_RDONLY,表示以只讀的方式共享內存,默認爲0表示以讀寫的方式共享內存。
函數返回值:調用成功則返回被映射的段地址,否則返回−1。
shmdt函數
Shmdt函數用來撤銷映射,其函數原型如下:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int shmdt(const void *shmaddr)
傳入參數Shmaddr表示被映射的共享內存段地址。函數成功則返回0,否則返回−1。
案例
sharwrite.c
/* ************************************************************************
* Filename: sharewrite.c
* Description:
* Version: 1.0
* Created: 05/09/2020 02:45:05 AM
* Revision: none
* Compiler: gcc
* Author: YOUR NAME (WCT),
* Company:
* ************************************************************************/
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
typedef struct{
char name[4];
int age;
} people;
int main(int argc, char** argv)
{
int shm_id,i;
key_t key;
char temp;
people *p_map;
char* name = "/home/wct/IPC";
key = ftok(name,0); // 將文件或目錄路徑轉換爲鍵值
if(key==-1){
perror("ftok error");
}
shm_id=shmget(key,4096,IPC_CREAT);
if(shm_id==-1)
{
perror("shmget error");
return -1;
}
p_map=(people*)shmat(shm_id,NULL,0);
temp='a' - 1;
for(i = 0;i<10;i++)
{
temp+=1;
memcpy((*(p_map+i)).name,&temp,1);
(*(p_map+i)).age=20+i;
}
if(shmdt(p_map)==-1){
perror(" detach error ");
}
return 0;
}
shareread.c
/* ************************************************************************
* Filename: shareread.c
* Description:
* Version: 1.0
* Created: 05/09/2020 03:08:12 AM
* Revision: none
* Compiler: gcc
* Author: YOUR NAME (),
* Company:
* ************************************************************************/
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
typedef struct{
char name[4];
int age;
} people;
int main(){
int shm_id, i;
key_t key;
people * p_map;
key = ftok("/home/wct/IPC", 0); // 將文件或目錄路徑轉換爲鍵值
if( key == -1 ){
perror("ftok error");
}
shm_id = shmget(key, 4096, IPC_CREAT);
if( shm_id == -1 ){
perror("shmget error");
return -1;
}
p_map = ( people * ) shmat(shm_id, NULL, 0);
for( i = 0; i < 10; i ++ ){
printf("name: %s\tage: %d\n", ( * ( p_map + i)).name, ( *( p_map + i )).age);
}
if( shmdt( p_map) == -1 ){
perror("detach error");
}
return 0;
}
編譯運行
編譯後直接 ./
運行會發現程序出現段錯誤,這是權限原因,加上sudo 即可。
當然了這裏不能同時運行這兩個程序,因爲這裏沒有加任何的同步機制。你可以自行加上同步機制,然後就可以同時運行了。