文章目錄
- 1. 共享記憶體原理及圖解
- 2. 共享記憶體相關函式及命令
- 2.1 創建共享記憶體函式
- 2.2 查看共享記憶體命令
- 2.3 洗掉共享記憶體命令
- 2.4 創建共享記憶體時賦予讀寫權限
- 2.5 將自定義的共享記憶體映射到行程虛擬地址的共享區中
- 2.6 單行程對共享記憶體進行的讀寫操作
- 2.7 多行程讀寫分離操作共享記憶體
- 2.8 將共享記憶體與行程進行分離
- 2.9 操作共享記憶體屬性
- 2.10洗掉共享記憶體總結
1. 共享記憶體原理及圖解
共享記憶體通過頁表映射到行程的行程虛擬地址空間的共享區中,行程通過操控共享區的內容,間接操作共享記憶體中的內容
不同的行程將同一塊共享記憶體映射到自己的共享區中,通過操作各自的共享區,以達到行程間資料交換

2. 共享記憶體相關函式及命令
2.1 創建共享記憶體函式
shmget函式
int shmget(key_t key, size_t size, int shmflg);
功能:開辟一段共享記憶體,用共享記憶體識別符號key去標識這塊記憶體,并回傳共享記憶體的操作句柄
頭檔案:
- sys/ipc.h
- sys/shm.h
引數:
- key : 共享記憶體識別符號,相當于共享記憶體的身份證,唯一標識共享記憶體區域
- size : 需要開辟的共享記憶體大小,單位是位元組
- shmflg
| 宏 | 含義 |
|---|---|
| IPC_CREAT | 若共享記憶體不存在,則創建 |
| IPC_EXCL | 與IPC_CREAT一同使用,為了確保共享記憶體已經存在時,會報告錯誤 |
回傳值:創建成功回傳 共享記憶體操作句柄 ,創建失敗回傳 -1
共享記憶體識別符號:用于唯一標識某塊共享記憶體的,行程可以通過共享記憶體識別符號找到這塊共享記憶體
共享記憶體操作句柄:用于操作這塊記憶體的
代碼演示shmget函式
#include <stdio.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define KEY 0x89898989
int main()
{
int shmid = shmget(KEY,1024,IPC_CREAT);
if(shmid < 0)
{
perror("shmget");
return -1;
}
printf("shmid : %d\n",shmid);
return 0;
}
[gongruiyang@localhost Testshm]$ ./shm
shmid : 425985
2.2 查看共享記憶體命令
ipcs命令用于查看所有行程間通信(IPC)資訊,-m選項是所有資訊中過濾出共享記憶體段的行程間通信資訊
ipcs -m
命令演示
[gongruiyang@localhost Testshm]$ ipcs -m
------------ 共享記憶體段 --------------
key shmid owner 權限 位元組 nattch status
0x00000000 262144 gongruiyan 600 524288 2 dest
0x89898989 425985 gongruiyan 0 1024 0 dest
0x00000000 393218 gongruiyan 600 524288 2 dest
- key : 共享記憶體識別符號,若為
- shmid : 共享記憶體操作句柄
- owner : 所屬用戶,誰創建的
- 權限 : 對該共享記憶體的操作權限
- 位元組 : 共享記憶體大小
- nattch : 附加的行程數量
- status : 共享記憶體段的狀態,dest表示銷毀
上面的程式創建了一個行程識別符號為0x89898989的共享記憶體段,雖然程式已經執行結束,但是共享記憶體段仍然存在,說明共享記憶體的生命周期的結束不是跟隨程式的,而是跟隨內核的
2.3 洗掉共享記憶體命令
ipcrm用于洗掉行程間通信資源,-m代表洗掉的是共享記憶體段
ipcrm -m 共享記憶體操作句柄
命令演示
[gongruiyang@localhost Testshm]$ ipcs -m
------------ 共享記憶體段 --------------
key shmid owner 權限 位元組 nattch status
0x00000000 262144 gongruiyan 600 524288 2 dest
0x89898989 425985 gongruiyan 0 1024 0 dest
0x00000000 393218 gongruiyan 600 524288 2 dest
[gongruiyang@localhost TestPipeCS]$ ipcrm -m 425985
[gongruiyang@localhost TestPipeCS]$ ipcs -m
------------ 共享記憶體段 --------------
鍵 shmid 擁有者 權限 位元組 nattch 狀態
0x00000000 262144 gongruiyan 600 524288 2 dest
0x00000000 393218 gongruiyan 600 524288 2 dest
2.4 創建共享記憶體時賦予讀寫權限
由上面程式創建出來的共享記憶體的權限為0可以看出,我們對該共享記憶體無任何權限,我們可以在創建共享記憶體的時候對共享記憶體屬性進行修改,增加 權限
int shmid = shmget(KEY,1024,IPC_CREAT | 0664);
2.5 將自定義的共享記憶體映射到行程虛擬地址的共享區中
void *shmat(int shmid, const void *shmaddr, int shmflg);
功能:將指定的共享記憶體段映射到行程虛擬地址的共享區中的某一塊中
頭檔案:
- sys/types.h
- sys/shm.h
引數:
- shmid : 共享記憶體操作句柄
- shmaddr : 映射到共享區的哪一塊地址,需要映射到哪一塊地址就填哪塊地址;如果填入NULL就代表想讓作業系統替我們選擇一個合適的地址,
- shmflg :
| 宏 | 含義 |
|---|---|
| SHM_RDONLY | 規定當前行程對該共享記憶體有 只讀權限 |
| 0 | 規定當前行程對該共享記憶體有 讀寫權限 |
回傳值:回傳 映射到的共享區 的地址
程式演示
#include <stdio.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define KEY 0x89898989
int main()
{
int shmid = shmget(KEY,1024,IPC_CREAT | 0664);
if(shmid < 0)
{
perror("shmget");
return -1;
}
void* lp = shmat(shmid,NULL,0); //讓系統分配共享區,該行程對共享記憶體的權限為 可讀可寫
printf("%p\n",lp);
return 0;
}
[gongruiyang@localhost Testshm]$ ./shm
0xffffffffffffffff
2.6 單行程對共享記憶體進行的讀寫操作
程式思路:
- 創建一塊共享記憶體識別符號為KEY的共享記憶體
- 將創建出來的共享記憶體附加到本行程中,讓系統分配共享區,權限為讀寫
- 本行程向共享記憶體中寫入資料
- 本行程從共享記憶體中讀取資料
程式演示:單行程對共享記憶體進行讀寫操作
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define KEY 0x89898989
int main()
{
//1.創建一塊共享記憶體識別符號為KEY的共享記憶體
int shmid = shmget(KEY,1024,IPC_CREAT | 0664);
if(shmid < 0)
{
perror("shmget");
return -1;
}
//2.將創建出來的共享記憶體附加到本行程中,讓系統分配共享區,權限為讀寫
void* lp = shmat(shmid,NULL,0);
//3.本行程向共享記憶體中寫入資料
const char* w_buf = "Hello World!\n";
strcpy((char*)lp,w_buf);
//4.本行程從共享記憶體中讀取資料
printf("%s\n",lp);
return 0;
}
2.7 多行程讀寫分離操作共享記憶體
程式演示:一個行程寫入資料 一個行程讀取資料
讀行程
#include <stdio.h>
#include <unistd.h>
#include <sys/shm.h>
#include <string.h>
#define KEY 0x89898989
int main()
{
int shmid = shmget(KEY, 1024, IPC_CREAT | 0664);
if(shmid < 0)
{
perror("shmget");
return -1;
}
void* lp = shmat(shmid, NULL, 0);
printf("%s\n", (char*)lp);
while(1)
{
sleep(1);
}
return 0;
}
寫行程
#include <stdio.h>
#include <unistd.h>
#include <sys/shm.h>
#include <string.h>
#define KEY 0x89898989
int main()
{
int shmid = shmget(KEY, 1024, IPC_CREAT | 0664);
if(shmid < 0)
{
perror("shmget");
return -1;
}
const char* w_buf = "Hello World!\n";
void* lp = shmat(shmid, NULL, 0);
strcpy((char*)lp, w_buf);
while(1)
{
sleep(1);
}
return 0;
}
行程讀取共享記憶體中資料時,并不會將共享記憶體中的資料拿走,資料依然存在共享記憶體之中
2.8 將共享記憶體與行程進行分離
int shmdt(const void *shmaddr);
功能:將行程中附加到共享區的某個共享記憶體段進行分離開
頭檔案:
- sys/types.h
- sys/shm.h
引數:
- shmaddr : shmat回傳值
回傳值:0 代表分離成功 ; -1 代表分離失敗
程式演示
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define KEY 0x89898989
int main()
{
//1.創建一塊共享記憶體識別符號為KEY的共享記憶體
int shmid = shmget(KEY,1024,IPC_CREAT | 0664);
if(shmid < 0)
{
perror("shmget");
return -1;
}
//2.將創建出來的共享記憶體附加到本行程中,讓系統分配共享區,權限為讀寫
void* lp = shmat(shmid,NULL,0);
while(1)
{
sleep(1);
}
return 0;
}
[gongruiyang@localhost Testshm]$ ipcs -m
------------ 共享記憶體段 --------------
鍵 shmid 擁有者 權限 位元組 nattch 狀態
0x00000000 262144 gongruiyan 600 524288 2 dest
0x89898989 524289 gongruiyan 664 1024 1
0x00000000 393218 gongruiyan 600 524288 2 dest
由此可以看出:附加在 共享記憶體識別符號為0x89898989 上的行程數量nattch為1
行程分離后的程式及現象
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define KEY 0x89898989
int main()
{
//1.創建一塊共享記憶體識別符號為KEY的共享記憶體
int shmid = shmget(KEY,1024,IPC_CREAT | 0664);
if(shmid < 0)
{
perror("shmget");
return -1;
}
//2.將創建出來的共享記憶體附加到本行程中,讓系統分配共享區,權限為讀寫
void* lp = shmat(shmid,NULL,0);
//將本行程與共享記憶體分離
int ret_shmdt = shmdt(lp);
if(ret_shmdt < 0)
perror("shmdt");
else
printf("shmdt success!\n");
while(1)
{
sleep(1);
}
return 0;
}
[gongruiyang@localhost Testshm]$ ipcs -m
------------ 共享記憶體段 --------------
鍵 shmid 擁有者 權限 位元組 nattch 狀態
0x00000000 262144 gongruiyan 600 524288 2 dest
0x89898989 557057 gongruiyan 664 1024 0
0x00000000 393218 gongruiyan 600 524288 2 dest
2.9 操作共享記憶體屬性
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
功能:操作共享記憶體的屬性
頭檔案:
- sys/types.h
- sys/shm.h
引數:
- shhmid : 共享記憶體操作句柄
- cmd : 告訴shmctl函式需要做什么操作,操作可以填入以下的宏
| 宏 | 含義 |
|---|---|
| IPC_STAT | 獲取共享記憶體屬性,將指定的共享記憶體屬性填入buf中 |
| IPC_SET | 設定共享記憶體數,將指定的共享記憶體屬性按照buf設定 |
| IPC_RMID | 刪除共享記憶體,buf直接傳遞NULL |
- buf : 共享記憶體結構體
shmid_ds結構體原始碼
struct shmid_ds {
struct ipc_perm shm_perm; /* Ownership and permissions */
size_t shm_segsz; /* Size of segment (bytes) */
time_t shm_atime; /* Last attach time */
time_t shm_dtime; /* Last detach time */
time_t shm_ctime; /* Last change time */
pid_t shm_cpid; /* PID of creator */
pid_t shm_lpid; /* PID of last shmat(2)/shmdt(2) */
shmatt_t shm_nattch; /* No. of current attaches */
...
};
struct ipc_perm {
key_t __key; /* Key supplied to shmget(2) */
uid_t uid; /* Effective UID of owner */
gid_t gid; /* Effective GID of owner */
uid_t cuid; /* Effective UID of creator */
gid_t cgid; /* Effective GID of creator */
unsigned short mode; /* Permissions + SHM_DEST and SHM_LOCKED flags */
unsigned short __seq; /* Sequence number */
};
程式演示:獲取共享記憶體屬性,并輸出共享記憶體大小
#include <stdio.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define KEY 0x89898989
int main()
{
int shmid = shmget(KEY,1024,IPC_CREAT | 0664);
if(shmid < 0)
{
perror("shmget");
return -1;
}
struct shmid_ds buf;
shmctl(shmid, IPC_STAT, &buf);
// 獲取 共享記憶體段 大小
printf("shm size : %ld位元組\n",buf.shm_segsz);
return 0;
}
[gongruiyang@localhost Testshm]$ ./shm
shm size : 1024位元組
2.10洗掉共享記憶體總結
- 當使用ipcrm命令或者shmctl函式洗掉共享記憶體之后,共享記憶體段就被釋放了
- 共享記憶體識別符號被設定為0x00000000,表示任何行程都無法通過之前的識別符號來尋找該共享記憶體
- 共享記憶體的狀態會被設定成dest(destroy),表示被銷毀
- 如果這塊被釋放的共享記憶體塊依然還有行程映射,即nattch不為0,則描述共享記憶體的結構體就不會被釋放,直到所有依附于該共享記憶體的行程全部分離后,即nattch為0時,描述該共享記憶體的結構體才會被釋放
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/243891.html
標籤:其他
