進程間通訊之共享內存css
1、什麼是共享內存ide
顧名思義,共享內存就是容許兩個不相關的進程訪問同一個邏輯內存。共享內存是在兩個正在運行的進程之間共享和傳遞數據的一種很是有效的方式。不一樣進程之間共享的內存一般安排爲同一段物理內存。進程能夠將同一段共享內存鏈接到它們本身的地址空間中,全部進程均可以訪問共享內存中的地址,就好像它們是由用C語言函數malloc分配的內存同樣。而若是某個進程向共享內存寫入數據,所作的改動將當即影響到能夠訪問同一段共享內存的任何其餘進程。函數
特別提醒:共享內存並未提供同步機制,也就是說,在第一個進程結束對共享內存的寫操做以前,並沒有自動機制能夠阻止第二個進程開始對它進行讀取。因此咱們一般須要用其餘的機制來同步對共享內存的訪問,例如信號量。ui
(信號量參考http://11418774.blog.51cto.com/11408774/1833222)。spa
2、共享內存的使用指針
與信號量同樣,在Linux中也提供了一組函數接口用於使用共享內存,並且使用共享共存的接口還與信號量的很是類似,並且比使用信號量的接口來得簡單。它們聲明在頭文件 sys/shm.h中。orm
一、shmget函數blog
該函數用來建立共享內存,它的原型爲:接口
int shmget(key_t key, size_t size, int shmflg);進程
第一個參數,與信號量的semget函數同樣,程序須要提供一個參數key(非0整數),它有效地爲共享內存段命名,shmget函數成功時返回一個與key相關的共享內存標識符(非負整數),用於後續的共享內存函數。調用失敗返回-1.
不相關的進程能夠經過該函數的返回值訪問同一共享內存,它表明程序可能要使用的某個資源,程序對全部共享內存的訪問都是間接的,程序先經過調用shmget函數並提供一個鍵,再由系統生成一個相應的共享內存標識符(shmget函數的返回值),只有shmget函數才直接使用信號量鍵,全部其餘的信號量函數使用由semget函數返回的信號量標識符。
第二個參數,size以字節爲單位指定須要共享的內存容量
第三個參數,shmflg是權限標誌,它的做用與open函數的mode參數同樣,若是要想在key標識的共享內存不存在時,建立它的話,能夠與IPC_CREAT作或操做。共享內存的權限標誌與文件的讀寫權限同樣,舉例來講,0644,它表示容許一個進程建立的共享內存被內存建立者所擁有的進程向共享內存讀取和寫入數據,同時其餘用戶建立的進程只能讀取共享內存。
二、shmat函數
第一次建立完共享內存時,它還不能被任何進程訪問,shmat函數的做用就是用來啓動對該共享內存的訪問,並把共享內存鏈接到當前進程的地址空間。它的原型以下:
void *shmat(int shm_id, const void *shm_addr, int shmflg);
第一個參數,shm_id是由shmget函數返回的共享內存標識。
第二個參數,shm_addr指定共享內存鏈接到當前進程中的地址位置,一般爲空,表示讓系統來選擇共享內存的地址。
第三個參數,shm_flg是一組標誌位,一般爲0。
調用成功時返回一個指向共享內存第一個字節的指針,若是調用失敗返回-1.
三、shmdt函數
該函數用於將共享內存從當前進程中分離。注意,將共享內存分離並非刪除它,只是使該共享內存對當前進程再也不可用。它的原型以下:
int shmdt(const void *shmaddr);
參數shmaddr是shmat函數返回的地址指針,調用成功時返回0,失敗時返回-1.
四、shmctl函數
與信號量的semctl函數同樣,用來控制共享內存,它的原型以下:
int shmctl(int shm_id, int command, struct shmid_ds *buf);
第一個參數,shm_id是shmget函數返回的共享內存標識符。
第二個參數,command是要採起的操做,它能夠取下面的三個值 :
IPC_STAT:把shmid_ds結構中的數據設置爲共享內存的當前關聯值,即用共享內存的當前關聯值覆蓋shmid_ds的值。
IPC_SET:若是進程有足夠的權限,就把共享內存的當前關聯值設置爲shmid_ds結構中給出的值
IPC_RMID:刪除共享內存段
第三個參數,buf是一個結構指針,它指向共享內存模式和訪問權限的結構。
shmid_ds結構至少包括如下成員:
struct shmid_ds
{
uid_t shm_perm.uid;
uid_t shm_perm.gid;
mode_t shm_perm.mode;
};
舉個例子
建立一個共享內存,兩個進程一個讀,一個寫,沒有同步機制,寫進程每隔1秒往內存中寫一個‘A’,而後讀進程每隔1秒讀出共享內存中的數據並打印出來。
工程文件:
comm.h:封裝所需的函數聲明
comm.c:函數的實現
sever.c:服務端(讀進程)
client.c:客戶端(寫進程)
comm.h
#pragma once #include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <errno.h> #define _PROJ_NAME_ "./tmp" #define _PROJ_ID_ 0x6666 int create_shm(int size); int get_shm(); int destory_shm(int shm_id); void* attach(int shm_id); int detach(void* addr);
comm.c
#include "comm.h" static int comm_shm(int size, int flag) { key_t _key = ftok(_PROJ_NAME_, _PROJ_ID_); if(_key < 0) { perror("ftok"); return -1; } int shm_id = shmget(_key, size, flag); if(shm_id < 0) { perror("shmget"); return -2; } return shm_id; } int create_shm(int size) { int flag = IPC_CREAT | IPC_EXCL | 0644; return comm_shm(size, flag); } int get_shm() { int flag = IPC_CREAT; return comm_shm(0, flag); } int destory_shm(int shm_id) { int ret = shmctl(shm_id, IPC_RMID, NULL); if(ret < 0) { perror("shmctl"); return -1; } return 0; } void* attach(int shm_id) { return shmat(shm_id, NULL, 0); } int detach(void* addr) { return shmdt(addr); }
sever.c
//sever.c #include "comm.h" int main() { int shm_id = create_shm(4097); void* addr = attach(shm_id); while(1) { printf("%s\n", (char* )addr); sleep(1); } detach(addr); destory_shm(shm_id); return 0; }
client.c
//client.c #include "comm.h" int main() { int shm_id = get_shm(); char* addr = (char* )attach(shm_id); int index = 0; while(1) { addr[index++] = 'A'; addr[index] = '\0'; sleep(1); } detach(addr); return 0; }
運行結果