共用記憶體 IPC 原理 共用記憶體進程間通信機制主要用於實現進程間大量的數據傳輸,下圖所示為進程間使用共用記憶體實現大量數據傳輸的示意圖: 共用記憶體是在記憶體中單獨開闢的一段記憶體空間,這段記憶體空間有自己特有的數據結構,包括訪問許可權、大小和最近訪問的時間等。該數據結構定義如下: ~~~~ from /usr ...
共用記憶體 IPC 原理
共用記憶體進程間通信機制主要用於實現進程間大量的數據傳輸,下圖所示為進程間使用共用記憶體實現大量數據傳輸的示意圖:
共用記憶體是在記憶體中單獨開闢的一段記憶體空間,這段記憶體空間有自己特有的數據結構,包括訪問許可權、大小和最近訪問的時間等。該數據結構定義如下:
from /usr/include/linux/shm.h
struct shmid_ds {
struct ipc_perm shm_perm; /* operation perms 操作許可權 */
int shm_segsz; /* size of segment (bytes) 段長度大小 */
__kernel_time_t shm_atime; /* last attach time 最近attach時間 */
__kernel_time_t shm_dtime; /* last detach time 最近detach時間 */
__kernel_time_t shm_ctime; /* last change time 最近change時間 */
__kernel_ipc_pid_t shm_cpid; /* pid of creator 創建者pid */
__kernel_ipc_pid_t shm_lpid; /* pid of last operator 最近操作pid */
unsigned short shm_nattch; /* no. of current attaches */
unsigned short shm_unused; /* compatibility */
void *shm_unused2; /* ditto - used by DIPC */
void *shm_unused3; /* unused */
};
兩個進程在使用此共用記憶體空間之前,需要在進程地址空間與共用記憶體空間之間建立聯繫,即將共用記憶體空間掛載到進程中。
系統對共用記憶體做了以下限制:
#define SHMMAX 0x2000000 /* max shared seg size (bytes) 最大共用段大小 */
#define SHMMIN 1 /* min shared seg size (bytes) 最小共用段大小 */
#define SHMMNI 4096 /* max num of segs system wide */
#define SHMALL (SHMMAX/getpagesize()*(SHMMNI/16))
#define SHMSEG SHMMNI /* max shared segs per process */
Linux 共用記憶體管理
1.創建共用記憶體
#include <sys/ipc.h>
#include <sys/shm.h>
/*
* 第一個參數為 key 值,一般由 ftok() 函數產生
* 第二個參數為欲創建的共用記憶體段大小(單位為位元組)
* 第三個參數用來標識共用記憶體段的創建標識
*/
int shmget(key_t key, size_t size, int shmflg);
2.共用記憶體控制
#include <sys/ipc.h>
#include <sys/shm.h>
/*
* 第一個參數為要操作的共用記憶體標識符
* 第二個參數為要執行的操作
* 第三個參數為 shmid_ds 結構的臨時共用記憶體變數信息
*/
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
3.映射共用記憶體對象
系統調用 shmat() 函數實現將一個共用記憶體段映射到調用進程的數據段中,並返回記憶體空間首地址,其函數聲明如下:
#include <sys/types.h>
#include <sys/shm.h>
/*
* 第一個參數為要操作的共用記憶體標識符
* 第二個參數用來指定共用記憶體的映射地址,非0則為此參數,為0的話由系統分配
* 第三個參數用來指定共用記憶體段的訪問許可權和映射條件
*/
void *shmat(int shmid, const void *shmaddr, int shmflg);
4.分離共用記憶體對象
在使用完畢共用記憶體空間後,需要使用 shmdt() 函數調用將其與當前進程分離。函數聲明如下:
#include <sys/types.h>
#include <sys/shm.h>
/*
* 參數為分配的共用記憶體首地址
*/
int shmdt(const void *shmaddr);
共用記憶體在父子進程間遵循的約定
1.使用 fork() 函數創建一個子進程後,該進程繼承父親進程掛載的共用記憶體。
2.如果調用 exec() 執行一個新的程式,則所有掛載的共用記憶體將被自動卸載。
3.如果在某個進程中調用了 exit() 函數,所有掛載的共用記憶體將與當前進程脫離關係。
程式實例
申請一段共用記憶體,父進程在首地址處存入一整數,子進程讀出。
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#define SHM_SIZE 1024
int main()
{
int shm_id, pid;
int *ptr = NULL;
/* 申請共用記憶體 */
shm_id = shmget((key_t)1004, SHM_SIZE, IPC_CREAT | 0600);
/* 映射共用記憶體到進程地址空間 */
ptr = (int*)shmat(shm_id, 0, 0);
printf("Attach addr is %p \n", ptr);
*ptr = 1004;
printf("The Value of Parent is : %d \n", *ptr);
if((pid=fork()) == -1){
perror("fork Err");
exit(0);
}
else if(!pid){
printf("The Value of Child is : %d \n", *ptr);
exit(0);
}else{
sleep(1);
/* 解除映射 */
shmdt(ptr);
/* 刪除共用記憶體 */
shmctl(shm_id, IPC_RMID, 0);
}
return 0;
}
輸出結果: