共享記憶體 IPC 原理
共享記憶體進程間通訊機制主要用於實現進程間大量的資料傳輸,下圖所示為進程間使用共享記憶體實現大量資料傳輸的示意圖:

#共享記憶體是記憶體中單獨開啟的一段記憶體空間,這段記憶體空間有自己獨特的資料結構,包括存取權、大小和最近存取的時間等。此資料結構定義如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | from /usr/ include /linux/shm.h
struct shmid_ds {
struct ipc_perm shm_perm;
int shm_segsz;
__kernel_time_t shm_atime;
__kernel_time_t shm_dtime;
__kernel_time_t shm_ctime;
__kernel_ipc_pid_t shm_cpid;
__kernel_ipc_pid_t shm_lpid;
unsigned short shm_nattch;
unsigned short shm_unused;
void *shm_unused2;
void *shm_unused3;
};
|
登入後複製
兩個進程在使用此共享記憶體空間之前,需要在進程位址空間與共享記憶體空間之間建立聯繫,即將共享記憶體空間掛載到進程中。
系統對共享記憶體做了以下限制:
1 2 3 4 5 | #define SHMMAX 0x2000000
#define SHMMIN 1
#define SHMMNI 4096
#define SHMALL (SHMMAX/getpagesize()*(SHMMNI/16))
#define SHMSEG SHMMNI
|
登入後複製
Linux 共享記憶體管理
1.建立共享記憶體
#
1 | # include <sys> # include <sys></sys></sys>
|
登入後複製
登入後複製
/*
* 第一個參數為 key 值,一般由 ftok() 函數產生
* 第二個參數為想要建立的共享記憶體段大小(單位為位元組)
* 第三個參數用來標識共享記憶體段的建立標識
*/
1 | int shmget(key_t key, size_t size, int shmflg);
|
登入後複製
2.共享記憶體控制
#
1 | # include <sys> # include <sys></sys></sys>
|
登入後複製
登入後複製
/*
* 第一個參數為要操作的共享記憶體標識符
* 第二個參數為要執行的操作
* 第三個參數為 shmid_ds 結構的暫時共享記憶體變數資訊
*/
1 | int shmctl(int shmid, int cmd, struct shmid_ds *buf);
|
登入後複製
3.映射共享記憶體物件
#系統呼叫 shmat() 函數實作將一個共享記憶體段映射到呼叫程序的資料段中,並傳回記憶體空間首位址,其函數宣告如下:
1 2 3 | # include <sys>
# include <sys>
</sys></sys>
|
登入後複製
登入後複製
/*
* 第一個參數為要操作的共享記憶體標識符
* 第二個參數用來指定共享記憶體的映射位址,非0則為此參數,為0的話由系統分配
* 第三個參數用來指定共享記憶體段的存取權限和映射條件
*/
1 | void *shmat(int shmid, const void *shmaddr, int shmflg);
|
登入後複製
4.分離共享記憶體物件
#在使用完畢共享記憶體空間後,需要使用 shmdt() 函數呼叫將其與目前進程分開。函數宣告如下:
1 2 3 | # include <sys>
# include <sys>
</sys></sys>
|
登入後複製
登入後複製
/*
* 參數為分配的共享記憶體首位址
*/
1 | int shmdt( const void *shmaddr);
|
登入後複製
共享內存在父子進程間遵循的約定
#1.使用 fork() 函數建立子程序後,該程序繼承父親程序掛載的共享記憶體。
2.如果呼叫 exec() 執行一個新的程序,則所有掛載的共享記憶體將被自動卸載。
3.如果在某個進程中呼叫了 exit() 函數,所有掛載的共享記憶體將與目前進程脫離關係。
程式實例
申請一段共享內存,父進程在首地址存入一整數,子進程讀出。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | # include
# include <sys>
# include <sys>
# include <sys>
# include
# include
#define SHM_SIZE 1024
int main()
{
int shm_id, pid;
int *ptr = NULL;
</sys></sys></sys>
|
登入後複製
/* 申請共享記憶體 */
1 | shm_id = shmget((key_t)1004, SHM_SIZE, IPC_CREAT | 0600);
|
登入後複製
/* 映射共享記憶體到進程位址空間 */
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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);
|
登入後複製
/* 解除對映 */
/* 刪除共享記憶體 */
1 2 3 4 5 | shmctl(shm_id, IPC_RMID, 0);
}
return 0;
}
|
登入後複製
輸出結果:

#
以上是Linux進程間如何共享記憶體的詳細內容。更多資訊請關注PHP中文網其他相關文章!