- 共享記憶體允許多個程序共享一個給定的記憶體空間,程序可以直接讀寫記憶體,是以是IPC中速度最快的。
- Linux中,核心專門留出了一塊記憶體區作為共享記憶體區,用于多個程序交換資訊。需要通信的程序将共享記憶體區映射到自己的私有位址空間,進而使讀寫程序位址空間就相當于讀寫記憶體區。使用共享記憶體的頭檔案是#include <sys/shm.h>
- 由于多個程序讀寫同一塊記憶體區,是以需要進行同步處理,一般要和信号量聯合使用(也可使用互斥量和記錄鎖)。
- 共享記憶體段預設是32M位元組。
- 共享記憶體的操作流程(隻使用于相關程序,即親緣程序間的通信):
- 建立/打開一塊共享記憶體區
- 把指定的共享記憶體映射到程序的位址空間
- 撤銷共享記憶體映射
- 删除共享記憶體對象(key代表的IPC對象)
- 共享記憶體常用函數:
- shmget(key, size, flag):建立新的共享記憶體段或者取得已有的共享記憶體段,函數傳回共享存儲段的ID(shmid)。key辨別共享記憶體的鍵值,兩個程序用相同的key時用shmget得到的shmid是相同的,此時可以通路同一塊共享記憶體。size表示獲得的共享記憶體大小。flag表示共享記憶體塊的通路權限,如果想共享記憶體段不存在時建立一個,用IPC_CREAT與權限值做位與操作即可。
- shmat(shmid, addr, flag):将共享存儲段映射到程序的位址空間。應當制定addr為0,由系統選擇位址(該位址位于堆棧之間)。 flag是一組标志位,一般也為0。調用成功後,傳回指向共享記憶體第一個位元組的指針。
- shmdt(addr):将程序位址空間與該共享記憶體段分離,使該共享記憶體對目前程序而言不可用。
- shmctl(shm_id, command, buf):控制共享記憶體。command參數:IPC_RMID(删除共享記憶體段)、IPC_STAT和IPC_SET(不常用)
- 無關程序(非親緣程序)共享記憶體的方法:
- 使用XSI共享存儲函數
- 使用mmap将同一檔案映射到多個程序的位址空間,為此要使用MAP_SHARED标志以保證:一個程序寫到存儲段,另一個程序可見。
- 使用共享記憶體的優缺點:
- 優點:友善,接口簡單;資料不用傳送而是直接讀寫記憶體,效率高;沒有無名管道那種親緣程序才能通信的限制,适用于不相關程序通信。
- 缺點:需要借助外部的同步機制
- 共享記憶體的使用例子,建立兩個程序,shmwrite向共享記憶體寫資料,shmread從共享記憶體讀資料:
- shmread程序,建立一塊共享記憶體段,将共享記憶體段映射到自己的記憶體空間,從記憶體中讀資料。
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/shm.h>
struct shared_use_st
{
int wirte_read_flag; //作為一個标志,非0:表示可讀,0表示可寫
char text[1024]; //記錄寫入和讀取的文本
};
int main()
{
int running = 1; //程式是否繼續運作的标志
void *shm = NULL; //配置設定的共享記憶體的原始首位址
struct shared_use_st *shared; //指向shm
int shmid; //共享記憶體辨別ID号
//建立共享記憶體,當key一樣時傳回的shmid也是一樣的,則兩個程序使用同一塊共享記憶體,IPC_CREAT表示建立一塊指定key的共享記憶體塊
shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666|IPC_CREAT);
if(shmid == -1)
{
fprintf(stderr, "shmget failed
");
exit(EXIT_FAILURE);
}
//将共享記憶體連接配接到目前程序的位址空間
shm = shmat(shmid, 0, 0);
if(shm == (void*)-1)
{
fprintf(stderr, "shmat failed
");
exit(EXIT_FAILURE);
}
printf("
Memory attached at %X
", (int)shm);
//設定共享記憶體
shared = (struct shared_use_st*)shm;
shared->wirte_read_flag = 0; //設為可寫
while(running) //讀取共享記憶體中的資料
{
//可讀模式,從程序的位址空間shm裡讀就相當于從共享記憶體裡讀
if(shared->wirte_read_flag != 0)
{
printf("Receive Message: %s", shared->text);
sleep(rand() % 3);
//讀取完資料,設定wirte_read_flag使共享記憶體段可寫
shared->wirte_read_flag = 0;
//輸入了end,退出循環
if(strncmp(shared->text, "end", 3) == 0)
running = 0;
}
else //有其他程序在寫資料,不能讀取資料
sleep(1);
}
//把共享記憶體從目前程序中分離
if(shmdt(shm) == -1)
{
fprintf(stderr, "shmdt failed
");
exit(EXIT_FAILURE);
}
//删除共享記憶體
if(shmctl(shmid, IPC_RMID, 0) == -1)
{
fprintf(stderr, "shmctl(IPC_RMID) failed
");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
-
- shmwrite程序,取得共享記憶體,将共享記憶體映射到自己的記憶體空間,向記憶體中寫資料。
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/shm.h>
struct shared_use_st
{
int wirte_read_flag; //作為一個标志,非0:表示可讀,0表示可寫
char text[1024]; //記錄寫入和讀取的文本
};
int main()
{
int running = 1;
void *shm = NULL;
struct shared_use_st *shared = NULL;
char buffer[1024 + 1]; //用于儲存輸入的文本
int shmid;
//建立共享記憶體,當key一樣時,傳回的shmid也是一樣的,則兩個程序通路同一塊共享記憶體,IPC_CREAT表示建立一塊指定key的共享記憶體
shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666|IPC_CREAT);
if(shmid == -1)
{
fprintf(stderr, "shmget failed
");
exit(EXIT_FAILURE);
}
//将共享記憶體連接配接到目前程序的位址空間
shm = shmat(shmid, (void*)0, 0);
if(shm == (void*)-1)
{
fprintf(stderr, "shmat failed
");
exit(EXIT_FAILURE);
}
printf("Memory attached at %X
", (int)shm);
//設定共享記憶體
shared = (struct shared_use_st*)shm;
while(running) //向共享記憶體中寫資料
{
//資料還沒有被讀取,則等待資料被讀取,不能向共享記憶體寫
while(shared->wirte_read_flag == 1)
{
sleep(1);
printf("Waiting...
");
}
//向共享記憶體中寫入資料,向程序的位址空間shm裡寫就相當于往共享記憶體裡寫!
printf("Enter some text: ");
fgets(buffer, BUFSIZ, stdin);
strncpy(shared->text, buffer, 1024);
//寫完資料,設定written使共享記憶體段可讀
shared->wirte_read_flag = 1;
//輸入了end,退出循環
if(strncmp(buffer, "end", 3) == 0)
running = 0;
}
//把共享記憶體從目前程序中分離
if(shmdt(shm) == -1)
{
fprintf(stderr, "shmdt failed
");
exit(EXIT_FAILURE);
}
sleep(2);
exit(EXIT_SUCCESS);
}
(ps:以上程式轉自http://blog.csdn.net/ljianhui/article/details/10253345)