共享內存
共享內存是允許兩個或多個進程共享同一塊內存區域,因爲進程可以直接讀寫內存,不需要任何數據的拷貝,這是一種最快的進程間通信方式。共享內存是多進程之間的通信方法 ,這種方法通常用於一個程序的多進程間通信,實際上多個程序間也可以通過共享內存來傳遞信息。當然,多個進程同時訪問共享區就得需要一些同步機制,如信號量或互斥鎖等,這些以後再記錄,本文先講最簡單的共享內存使用方式。
linux共享內存操作的四個函數
shmget函數:創建一個共享內存對象並返回共享內存標識符。
shmat函數:把創建的共享內存映射到具體的進程空間去,映射後就可以在本進程使用這塊地址。
shmctl函數:共享內存管理,完成對共享內存的控制。
shmdt函數:撤銷映射共享內存,但是並不刪除所指定的共享內存區,而只是將先前用shmat函數連接好的共享內存脫離目前的進程。
shmget 函數
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key,int size,int shmflg)
返回值:若成功,返回共享內存段標識符;若出錯,返回-1
參數說明:
- Key:IPC_PRIVATE (爲0,比較常見的一種)
- Size:共享內存區大小
- Shmflg:同 open 函數的權限位,也可以用八進制表示法
shmat函數
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
char *shmat(int shmid,const void *shmaddr,int shmflg)
返回值:若成功,返回被映射的段地址;若出錯,返回-1
參數說明:
- shmid:要映射的共享內存區標識符
- shmaddr:將共享內存映射到指定位置(若爲 0 則表示把該段共享內存映射到調用進程的地址空間)
- Shmflg
- SHM_RDONLY:共享內存只讀
- 默認 0:共享內存可讀寫
shmctl函數
#include <sys/types.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf)
返回值:若成功,返回0;若出錯,返回-1
參數含義:
- shmid:共享內存標識符
cmd:
- IPC_STAT:得到共享內存的狀態,把共享內存的shmid_ds結構複製到buf中
- IPC_SET:改變共享內存的狀態,把buf所指的shmid_ds結構中的uid、gid、mode複製到共享內存的shmid_ds結構內
- IPC_RMID:刪除這片共享內存
buf:共享內存管理shmid_ds結構體。
以下是 shmid_ds 結構:
struct shmid_ds
{
struct ipc_perm shm_perm; /* operation permission struct */
size_t shm_segsz; /* size of segment in bytes */
pid_t shm_lpid; /* pid of last shmop() operation */
pid_t shm_cpid; /* pid of creator */
shmatt_t shm_nattch; /* number of current attaches */
time_t shm_atime; /* last-attach time */
time_t shm_dtime; /* last-detach time */
time_t shm_ctime; /* last-change time */
};
shmdt函數
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int shmdt(const void *shmaddr)
返回值:若成功,返回0;若出錯,返回-1
參數說明:
- Shmaddr:被映射的共享內存段地址
示例程序
/* share_memory.c*/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/shm.h>
#define BUFF 1024
int main ()
{
int shmid;
pid_t pid;
char *shmaddr;//共享內存地址
/*創建共享內存*/
if((shmid=shmget(IPC_PRIVATE,BUFF,0666))<0)
{
perror("shmget");
exit(-1);
}
else
printf("Create shared memory,id = %d\n",shmid);
if ((pid = fork()) < 0)
{
perror("fork");
exit(-1);
}
else if (pid == 0) //子進程
{
/*映射共享內存*/
if((shmaddr=shmat(shmid,0,0))<(char *)0)
{
perror("shmat");
exit(-1);
}
else
printf("I am child,shmat shared memory success\n");
//子進程往共享內存寫數據
strcpy( shmaddr, "from child process\n");
//snprintf(shmaddr, 13, "%012d", 12345);
//本函數調用並不刪除所指定的共享內存區,而只是將先前用shmat函數連接(attach)好的共享內存脫離(detach)目前的進程
shmdt(shmaddr);
return 0;
}
else //父進程
{
//保證子進程已經往共享內存寫入數據了
sleep(2);
/*映射共享內存*/
if((shmaddr=shmat(shmid,0,0))<(char *)0)
{
perror("shmat");
exit(-1);
}
else
printf("I am parent,shmat shared memory success\n");
//讀取共享內存的數據
printf("read from share memory: %s",shmaddr);
shmdt(shmaddr);
//等待子進程退出
waitpid(pid,NULL,0);
exit(0);
}
return 0;
}
實驗結果:
ubuntu:~/test/process_test$ ./share_memory
Create shared memory,id = 0
I am child,shmat shared memory success
I am parent,shmat shared memory success
read from share memory: from child process
以上程序,我們調用shmget函數創建共享內存區,然後調用fork函數創建子進程,在子進程中調用shmat映射共享內存地址,然後往共享內存區寫數據。在父進程中,同樣調用shmat函數映射共享內存區,然後從共享內存區讀取子進程寫入的數據。
共享內存的簡單應用就說到這了,下次講消息隊列。