目錄
- 一、shmget/shmctl/shmat/shmdt函數
- 1、shmget
- 2、shmctl
- 3、shmat
- 4、shmdt
- 5、補充:ftok函數
- 6、示例代碼
- 二、shm_open/shm_unlink函數
- 1、shm_open
- 2、shm_unlink
- 3、示例代碼
- 三、課外閱讀
一、shmget/shmctl/shmat/shmdt函數
??shm_xx系列函數是用于操作共享內存的一組函數,它們通常包括shmget、shmctl、shmat和shmdt。下面對這些函數進行詳細解釋:
1、shmget
- 功能:創建一個新的共享內存段或獲取一個已經存在的共享內存段的標識符。
- 原型:
int shmget(key_t key, size_t size, int shmflg)
- 參數:
key
:用于識別共享內存段的鍵值,通常使用ftok
函數生成。size
:共享內存段的大小。單位是字節。shmflg
:打開標志,用于指定操作的方式,比如創建共享內存段、獲取共享內存標識符等。
- 返回值:成功時返回共享內存段的標識符(非負整數),失敗時返回-1。
shmget
函數是用于創建共享內存段、獲取共享內存標識符或者訪問一個已存在的共享內存段的函數,其聲明如下:
??shmget
函數的主要功能包括:
- 如果指定的
key
對應的共享內存段不存在,并且設置了創建標志(IPC_CREAT
),則會創建一個新的共享內存段,大小為size
字節。 - 如果指定的
key
對應的共享內存段存在,則會返回共享內存標識符。 - 如果不希望創建共享內存段,可以不設置
IPC_CREAT
標志。此時若指定的key
對應的共享內存段不存在,shmget
函數將會返回錯誤。
??shmget
函數的返回值是共享內存標識符(shmid),用于后續對共享內存段的訪問操作,比如連接共享內存、獲得共享內存的地址等。
??在使用 shmget
函數時,需要注意確保對共享內存的大小和權限的設置,避免潛在的問題,比如內存溢出或者權限不足等。同時,需要根據具體需求合理設置 shmflg
參數,確保對共享內存的訪問操作符合預期。
2、shmctl
- 功能:用于控制共享內存段。
- 原型:
int shmctl(int shmid, int cmd, struct shmid_ds *buf)
- 參數:
shmid
:是共享內存標識符,是由shmget
函數返回的。cmd
:是控制命令,用于指定對共享內存的具體操作,比如刪除共享內存段、獲取共享內存信息等。buf
:是指向shmid_ds
結構體的指針,用于傳遞或者獲取共享內存的信息。
- 返回值:成功時返回0,失敗時返回-1。
shmctl
函數是用于控制共享內存段的操作函數,主要用于對共享內存段進行控制操作,比如刪除、獲取信息等,其聲明如下:
shmctl
函數的主要功能包括:
- 獲取共享內存段的信息,比如共享內存大小、關聯進程數等。
- 控制共享內存段的權限,比如修改共享內存的權限。
- 刪除共享內存段。
cmd
參數可以取以下值之一:
IPC_STAT
:獲取共享內存的狀態信息,并將其存儲在buf
指向的結構體中。IPC_SET
:設置共享內存的狀態信息,更新共享內存的權限等。IPC_RMID
:刪除共享內存段,釋放資源。
??需要注意的是,在使用 shmctl
函數時,要根據具體需求選擇合適的控制命令,并確保傳入正確的參數,以免出現意外的錯誤。同時,刪除共享內存段時,需要注意確保所有關聯進程已經分離了共享內存段,否則刪除操作可能會失敗。
3、shmat
- 功能:將共享內存段連接到調用進程的地址空間。
- 原型:
void *shmat(int shmid, const void *shmaddr, int shmflg)
- 參數:
shmid
:是共享內存標識符,是由shmget
函數返回的。shmaddr
:是一個指針,用于指定將共享內存段映射到進程地址空間的地址,通常設為NULL
。shmflg
:參數用于指定連接共享內存段的標志,通常可以設置為 0。
- 返回值:成功時返回指向共享內存段起始地址的指針,失敗時返回-1。
??shmat
函數的主要作用是將共享內存段連接到當前進程的地址空間,實現進程對共享內存段的訪問。連接成功后,shmat
函數將返回一個指向共享內存段起始地址的指針,進程可以通過該指針來訪問共享內存段中的數據。
??一般情況下,shmaddr
參數設為 NULL
,由系統自動選擇合適的地址來映射共享內存段到進程地址空間中。shmflg
參數通常設為 0,表示默認的連接標志,除非有特殊需求,一般不需要修改。
??需要注意的是,在使用 shmat
函數時,要確保傳入正確的共享內存標識符 shmid
,避免出現連接錯誤。另外,在使用完共享內存后,要及時調用 shmdt
函數將共享內存段從當前進程地址空間中分離,避免資源泄漏。
4、shmdt
- 功能:將共享內存段從調用進程的地址空間中分離。
- 原型:
int shmdt(const void *shmaddr)
- 參數:
shmaddr
:是共享內存段連接到進程地址空間的起始地址,通常是由shmat
函數返回的。
- 返回值:成功時返回0,失敗時返回-1。
??shmdt
函數的主要作用是斷開當前進程與共享內存段的連接,使得進程無法再訪問共享內存段中的數據。調用 shmdt
函數后,共享內存段仍然存在,但當前進程無法再對其進行操作。
??在使用 shmdt
函數時,需要傳入正確的共享內存段起始地址 shmaddr
,確保將正確的共享內存段從當前進程中分離。另外,需要注意的是,分離共享內存段后,如果沒有其他進程仍然連接著該共享內存段,系統會釋放該共享內存段,從而釋放相關資源。
??在使用共享內存時,需要注意合理地管理共享內存的連接和分離,避免出現資源泄漏或者錯誤的操作。
ftok
函數是一個用于生成一個 System V IPC(Inter-Process Communication,進程間通信)鍵值的函數,其聲明如下:
5、補充:ftok函數
key_t ftok(const char *pathname, int proj_id);
pathname
參數是一個指向字符串的指針,用于指定一個已經存在的文件的路徑名。proj_id
參數是一個用戶定義的整數,可以是 0 到 255 的范圍內的任意值。
??ftok
函數會根據指定的 pathname
和 proj_id
生成一個唯一的鍵值,用于創建或訪問 System V IPC 的資源,如共享內存、信號量和消息隊列。
??實際上,ftok
函數根據 pathname
參數對應文件的 inode 號和 proj_id
參數生成一個 32 位的鍵值,最高 8 位存放 proj_id
,低 24 位存放 pathname
對應文件的 inode 號的后 24 位。這樣可以保證相同的 pathname
和 proj_id
參數生成相同的鍵值。
??需要注意的是,在使用 ftok
函數時要確保 pathname
參數是一個已經存在的文件的路徑名,否則會導致生成的鍵值不唯一。另外,proj_id
參數的取值范圍是 0 到 255,超出這個范圍可能導致鍵值重復。
??綜上所述,ftok
函數是用于生成 System V IPC 鍵值的一個實用工具函數,可以通過指定文件路徑和項目標識來確保生成唯一的鍵值,用于進程間通信的各種資源的創建和訪問。
6、示例代碼
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>#define SHM_SIZE 1024 // 共享內存大小int main() {key_t key = ftok("shmfile", 'R'); // 創建共享內存的鍵值int shmid;// 創建共享內存段shmid = shmget(key, SHM_SIZE, IPC_CREAT | 0666);if (shmid == -1) {perror("shmget");exit(1);}// 連接共享內存段char *shmaddr = (char *)shmat(shmid, NULL, 0);if (shmaddr == (char *)-1) {perror("shmat");exit(1);}// 寫入數據到共享內存strcpy(shmaddr, "Hello, Shared Memory!");printf("Data written to shared memory: %s\n", shmaddr);// 分離共享內存段if (shmdt(shmaddr) == -1) {perror("shmdt");exit(1);}// 刪除共享內存段if (shmctl(shmid, IPC_RMID, 0) == -1) {perror("shmctl");exit(1);}return 0;
}
二、shm_open/shm_unlink函數
1、shm_open
??shm_open
是 POSIX 標準中定義的用于創建或打開共享內存對象的函數。與傳統的 shmget
函數類似,shm_open
提供了一種不同的方式來管理共享內存,使用文件描述符來標識共享內存對象。shm_open
的原型如下:
int shm_open(const char *name, int oflag, mode_t mode);
name
參數是一個指向表示共享內存對象名稱的字符串的指針。共享內存對象通過名稱在文件系統中標識。oflag
參數指定了打開共享內存對象時的操作標志,可以是一組位或運算的標志,比如O_CREAT
(創建共享內存對象),O_RDWR
(可讀寫方式打開)等。mode
參數指定了新創建的共享內存對象的權限標志,通常與open
系統調用中使用的mode
參數一樣。
??使用 shm_open
函數創建或打開共享內存對象后,可以通過標準的文件 I/O 函數(如 read
和 write
)對共享內存進行讀寫操作。共享內存對象在文件系統中以名字為標識,不同進程可以通過相同的名字打開同一個共享內存對象,從而實現進程間通信。
??在使用 shm_open
函數時,需要注意以下幾點:
- 共享內存對象的名稱必須在當前系統中是唯一的,以避免命名沖突。
- 在打開共享內存對象后,應謹慎進行讀寫操作,避免發生競爭條件和數據一致性問題。
- 當不再需要共享內存對象時,應當使用
shm_unlink
函數來釋放該共享內存對象,以防止資源泄漏。
??總的來說,shm_open
提供了一種基于文件描述符的共享內存對象管理方式,使得共享內存在不同進程之間的使用更加靈活和方便。
2、shm_unlink
??shm_unlink
是一個函數,用于刪除由 shm_open
創建的共享內存對象的名稱。在 POSIX 標準中,共享內存對象在文件系統中以名稱標識,使用 shm_open
打開該共享內存對象后,可以通過 shm_unlink
函數刪除該對象的名字,但不會立即釋放共享內存本身。只有在所有進程都關閉該共享內存對象的文件描述符或調用 shm_unlink
之后,共享內存對象才會被徹底刪除。shm_unlink
的原型如下:
int shm_unlink(const char *name);
name
參數是一個指向表示要刪除的共享內存對象名稱的字符串的指針。
??使用 shm_unlink
函數可以確保在不再需要共享內存對象時清理對象的名稱,這樣可以避免其他進程再次通過該名稱打開共享內存對象。但需要注意的是,即使調用了 shm_unlink
,只有當所有打開該共享內存對象的文件描述符都關閉,共享內存對象才會被系統真正刪除。
??一般來說,在不再需要使用共享內存對象時,建議及時調用 shm_unlink
,以便及時釋放已不需要的資源。這樣可以更好地管理共享內存,避免資源泄漏和冗余共享內存對象的存在。
3、示例代碼
??以下是一個簡單的示例代碼,展示了如何使用 shm_open
和 shm_unlink
函數來創建和刪除共享內存對象的名稱。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>#define SHM_NAME "/my_shared_memory"
#define SHM_SIZE 1024int main() {const char *data = "Hello, this is shared memory demo!";// Create or open a shared memory objectint shm_fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);ftruncate(shm_fd, SHM_SIZE);// Map the shared memory object into memorychar *shm_ptr = mmap(0, SHM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);// Write data to the shared memorystrcpy(shm_ptr, data);printf("Data written to shared memory: %s\n", shm_ptr);// Unmap the shared memorymunmap(shm_ptr, SHM_SIZE);// Close the shared memory objectclose(shm_fd);// Unlink the shared memory object nameshm_unlink(SHM_NAME);return 0;
}
??在這個示例代碼中,首先使用 shm_open
函數創建或打開一個共享內存對象,并指定名稱為 "/my_shared_memory"
。然后使用 ftruncate
函數設置共享內存對象的大小為 SHM_SIZE
字節。
??接著,使用 mmap
函數將共享內存對象映射到當前進程的內存空間中,使得可以對其進行讀寫操作。將數據寫入共享內存后,通過 munmap
函數解除共享內存的映射,并通過 close
函數關閉共享內存對象的文件描述符。
??最后,調用 shm_unlink
函數刪除共享內存的名稱,這樣其他進程就無法再使用該名稱打開共享內存對象。
三、課外閱讀
推薦閱讀:進程間通信–共享內存篇
??歡迎大家指導和交流!如果我有任何錯誤或遺漏,請立即指正,我愿意學習改進。期待與大家一起進步!