概述
????????在Linux系統中,共享內存也是一種高效的進程間通信機制,允許兩個或多個進程共享同一塊物理內存區域。通過這種方式,不同進程可以直接訪問和操作相同的數據,從而避免了數據的復制。由于數據直接在內存中共享,沒有額外的數據傳輸過程,因此速度非常快。雖然共享內存本身提供了快速的數據交換方式,但它并不提供同步機制。這意味著,需要我們自己實現同步措施以防止競態條件。
API接口
????????在Linux中,主要通過以下幾個API接口來實現共享內存機制。
????????1、shmget:用于創建一個新的共享內存段,或獲取一個已存在的共享內存段。其函數原型如下。
int shmget(key_t key, size_t size, int shmflg);
????????各個參數和返回值的含義如下。
????????key:標識共享內存段的鍵值,通常使用ftok函數生成。
????????size:共享內存段的大小,以字節為單位。
????????shmflg:權限標志和創建標志(比如IPC_CREAT、IPC_EXCL等),以及訪問權限。
????????返回值:成功時,返回共享內存標識符。失敗時返回-1,可通過errno獲取具體的錯誤代碼。
????????2、shmat:將共享內存段連接到調用進程的地址空間。其函數原型如下。
void *shmat(int shmid, const void *shmaddr, int shmflg);
????????各個參數和返回值的含義如下。
????????shmid:由shmget函數返回的共享內存標識符。
????????shmaddr:指定共享內存段應連接到的地址,通常設置為NULL,讓系統自動選擇。
????????shmflg:控制共享內存段連接的方式,如SHM_RDONLY表示只讀。
????????返回值:成功時,返回指向共享內存段的指針。失敗時返回(void *) -1,可通過errno獲取具體的錯誤代碼。
????????3、shmdt:將共享內存段從調用進程的地址空間分離。其函數原型如下。
int shmdt(const void *shmaddr);
????????各個參數和返回值的含義如下。
????????shmaddr:由shmat返回的地址。
????????返回值:成功時,返回0。失敗時返回-1,可通過errno獲取具體的錯誤代碼。
????????4、shmctl:執行多種控制操作,如獲取共享內存段的狀態、設置共享內存段的狀態、刪除共享內存段等。其函數原型如下。
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
????????各個參數和返回值的含義如下。
????????shmid:由shmget函數返回的共享內存標識符。
????????cmd:命令ID,比如,IPC_STAT表示獲取狀態、IPC_SET表示設置狀態、IPC_RMID表示移除段。
????????buf:根據命令不同,可能需要提供一個指向struct shmid_ds結構體的指針。
????????返回值:成功時,返回0。失敗時返回-1,可通過errno獲取具體的錯誤代碼。
實戰代碼
????????在下面的實戰代碼中,我們使用共享內存機制來創建、寫入和分離一個共享內存段。
????????首先,通過調用ftok函數并傳入一個路徑名和一個項目ID,生成一個唯一的鍵值,該鍵值用于后續標識共享內存段。然后,利用shmget函數根據這個鍵值創建一個新的共享內存段。這里指定共享內存的大小為1024字節,并設置了權限標志,以確保創建時賦予讀寫權限給所有用戶。
????????一旦成功獲得共享內存段的標識符shmid,我們便通過shmat函數將這個共享內存段連接到當前進程的地址空間中。shmat會返回一個指向共享內存起始位置的指針,隨后,我們使用strcpy函數將字符串復制到該指針中。
????????最后,我們調用shmdt函數將共享內存段從當前進程的地址空間中進行了分離。
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <string.h>int main()
{// 創建唯一的鍵key_t key = ftok("shmfile", 66);// 創建共享內存段int shmid = shmget(key, 1024, 0666|IPC_CREAT);// 連接共享內存段char *pszBuffer = (char*)shmat(shmid, (void*)0, 0);strcpy(pszBuffer, "Hello, Hope_Wisdom");printf("Data written in memory: %s\n", pszBuffer);// 分離共享內存段shmdt(pszBuffer);return 0;
}
????????為了與上面的進程相配合,我們實現了下面的進程,使用共享內存機制來獲取、讀取和管理一個共享內存段。
????????首先,我們調用shmget函數根據鍵值獲取一個已經存在的共享內存段。這里指定共享內存的大小為1024字節,并設置了權限標志,以確保創建時賦予讀寫權限給所有用戶。
????????一旦成功獲得共享內存段的標識符shmid,我們便通過shmat函數將這個共享內存段連接到當前進程的地址空間中。shmat會返回一個指向共享內存起始位置的指針,隨后,我們直接嘗試從該指針讀取數據并打印出來。
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>int main()
{// 創建唯一的鍵key_t key = ftok("shmfile", 66);// 獲取共享內存段IDint shmid = shmget(key, 1024, 0666|IPC_CREAT);// 連接共享內存段char *pszBuffer = (char*)shmat(shmid, (void*)0, 0);printf("Data read from memory: %s\n", pszBuffer);// 分離共享內存段shmdt(pszBuffer);// 刪除共享內存段shmctl(shmid, IPC_RMID, NULL);return 0;
}