進程間通信的三大主題纖消息隊列、信號量、共享內存,還剩下最後一個模塊。下來我們就來看看這最後一個主題:共享內存。
共享內存
共享內存允許兩個或多個進程共享一個給定的存儲區。因爲共享內存數據不需要在進程和進程之間複製,所以共享內存是最快的一種IPC。
允許兩個或多個進程共享一個存儲區的意思是,同一塊物理內存被映射到這些進程各自的進程地址空間。這樣這些進程都可以看到其他進程對共享內存中數據的更新。
另外要注意的是共享內存和管道不同,共享內存不提供互斥與同步機制,所以當一個進程正在將數據放入共享內存中,那麼其他進程在它做完這一操作之前,不應該對共享內存進行數據寫入。通常通過信號量和互斥鎖實現互斥與同步。
共享內存相關函數
- shmget:創建共享內存
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
返回值:若成功,返回共享內存ID,若出錯,返回-1;
key和shmflg就不說了和前面創建其他IPC機制一樣。
需要知道的是參數size,這裏的size是共享內存段的長度,以字節爲單位,而操作系統爲你分配空間的時候是按照頁來分配的,所以size應該爲4k(一般一頁的大小)的整數倍。若size值不是整數倍,那麼最後一頁的餘下部分是不可使用的。
- shmat: 連接共享內存
一旦創建了一個共享內存,進程就可調用shmat將其連接到它的地址空間中。
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
返回值:若成功,返回指向共享內存的指針;若出錯,返回-1;
shmid是共享內存ID
共享內存段連接到調用進程的哪個地址上與addr以及shmflg有關。
一般addr設置爲NULL,shmflg設置爲0就可以了。
- shmdt:去關聯共享內存
當對共享內存段的操作已經結束時,則調用shmdt與該段分離。注意,這並不是從系統中刪除其標識符以及相關數據結構。該標識符仍然存在,知道某進程自己進行刪除
#include <sys/shm.h>
int shmdt(const void *shmaddr);
返回值:若成功,返回0,若出錯,返回-1;
shmaddr參數是shmat的返回值。如果成功,shmat將使相關shmid_ds數據結構中的shm_nattch計數器減1。
- shmctl:對共享內存段執行多種操作(刪除、取shmid_ds結構、加鎖、解鎖等)
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
返回值:若成功,返回0;若出錯,返回-1;
cmd:參數指定5種命令中的一種。最重要的就是刪除命令IPC_RMID。
buf:如果不需要取此段的shmid_ds就直接NULL就行了。
程序實例:
- shm.h
/*************************************************************************
> File Name: shm.h
> Author:
> Mail:
> Created Time: Tue 13 Jun 2017 05:46:14 AM PDT
************************************************************************/
#include<stdio.h>
#include<unistd.h>
#include<sys/shm.h>
#include<sys/ipc.h>
#include<sys/wait.h>
#define __PATH__ "."
#define __PROJECT__ 8888
#define __SHM_SIZE__ 4*1024 //4k對齊
//創建共享存儲區
int common_shm(int flag)
{
int key=ftok(__PATH__,__PROJECT__);
if(key==-1)
{
printf("ftok is faild!\n");
return -1;
}
return shmget(key,__SHM_SIZE__,flag);
}
int creat_shm()
{
return common_shm(IPC_CREAT|0666);
}
int get_shm()
{
return common_shm(0);
}
//連接已有的共享內存
void *at_shm(int shmid)
{
return (char*)shmat(shmid,NULL,0);
}
//進程與共享內存分離
int dt_shm(const void *addr)
{
return shmdt(addr);
}
//刪除共享內存
int destory_shm(int shmid)
{
return shmctl(shmid,IPC_RMID,NULL);
}
- client.c
/*************************************************************************
> File Name: client.c
> Author:
> Mail:
> Created Time: Tue 13 Jun 2017 06:16:21 AM PDT
************************************************************************/
#include"shm.h"
int main()
{
int shmid=get_shm();
if(shmid==-1)
{
printf("get_shm is faild!\n");
}
char *addr=at_shm(shmid);
sleep(1);
int i = 0;
while(1)
{
sleep(1);
addr[i++] = 'a';
i %= (__SHM_SIZE__-1);
addr[i]='\0';
}
dt_shm(addr);
return 0;
}
- server.c
/*************************************************************************
> File Name: server.c
> Author:
> Mail:
> Created Time: Tue 13 Jun 2017 06:50:10 AM PDT
************************************************************************/
#include"shm.h"
int main()
{
int shmid=creat_shm();
if(shmid==-1)
{
printf("creat_shm is faild!\n");
return -1;
}
sleep(5);
char *addr=at_shm(shmid);
while(1)
{
sleep(1);
printf("%s\n",addr);
}
sleep(5);
dt_shm(addr);
destory_shm(shmid);
return 0;
}