歡迎光臨
每天分享高質量文章

架構師進階:Linux行程間如何共享記憶體?


導讀 共享記憶體是在記憶體中單獨開闢的一段記憶體空間,這段記憶體空間有自己特有的資料結構,包括訪問許可權、大小和最近訪問的時間等。

共享記憶體 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  #include 

/*
* 第一個引數為 key 值,一般由 ftok() 函式產生
* 第二個引數為欲建立的共享記憶體段大小(單位為位元組)
* 第三個引數用來標識共享記憶體段的建立標識
*/

int shmget(key_t key, size_t size, int shmflg);

2.共享記憶體控制

#include  #include 

/*
* 第一個引數為要操作的共享記憶體識別符號
* 第二個引數為要執行的操作
* 第三個引數為 shmid_ds 結構的臨時共享記憶體變數資訊
*/

int shmctl(int shmid, int cmd, struct shmid_ds *buf);

3.對映共享記憶體物件

系統呼叫 shmat() 函式實現將一個共享記憶體段對映到呼叫行程的資料段中,並傳回記憶體空間首地址,其函式宣告如下:

#include 

#include

/*
* 第一個引數為要操作的共享記憶體識別符號
* 第二個引數用來指定共享記憶體的對映地址,非0則為此引數,為0的話由系統分配
* 第三個引數用來指定共享記憶體段的訪問許可權和對映條件
*/

void *shmat(int shmid, const void *shmaddr, int shmflg);

4.分離共享記憶體物件

在使用完畢共享記憶體空間後,需要使用 shmdt() 函式呼叫將其與當前行程分離。函式宣告如下:

#include 

#include

/*
* 引數為分配的共享記憶體首地址
*/

int shmdt(const void *shmaddr);

共享記憶體在父子行程間遵循的約定

1.使用 fork() 函式建立一個子行程後,該行程繼承父親行程掛載的共享記憶體。

2.如果呼叫 exec() 執行一個新的程式,則所有掛載的共享記憶體將被自動解除安裝。

3.如果在某個行程中呼叫了 exit() 函式,所有掛載的共享記憶體將與當前行程脫離關係。

程式實體

申請一段共享記憶體,父行程在首地址處存入一整數,子行程讀出。

#include

#include

#include

#include

#include

#include

#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;
}

輸出結果:

《Linux雲端計算及運維架構師高薪實戰班》2018年07月16日即將開課中,120天衝擊Linux運維年薪30萬,改變速約~~~~

    *宣告:推送內容及圖片來源於網路,部分內容會有所改動,版權歸原作者所有,如來源資訊有誤或侵犯權益,請聯絡我們刪除或授權事宜。

    – END –


    更多Linux好文請點選【閱讀原文】

    ↓↓↓

    贊(0)

    分享創造快樂

    © 2024 知識星球   網站地圖