本文詳解了通過共享記憶體進行行程間通信的方法,并對訊息佇列,信號量做了簡單介紹,
另一種行程間通信--管道,見前文:[OS-Linux]詳解Linux的行程間通信1------管道_RMA515T的博客-CSDN博客
管道通信本質是基于檔案,OS沒有過多的設計,
system V行程間通信是OS特地設計的通信方式,讓不同行程看到同一份資源,system V行程間通信包括了共享記憶體、訊息佇列、信號量,共享記憶體與訊息佇列以傳輸資料為目的,信號量則是保證行程的同步與互斥設計的,屬于通信的范疇,
目錄
一、system V共享記憶體
二、共享記憶體原理
1. 共享記憶體的通信原理
2. 共享記憶體資料結構
3.共享記憶體的建立程序
三、共享記憶體函式
1.shmget函式
2.shmat函式
3.shmdt函式
4. shmctl函式
三、共享記憶體實體
makefile
server.c
client.c
結果
四、system V訊息佇列
五、system V信號量
1.行程互斥
總結
一、system V共享記憶體
共享記憶體區是最快的IPC形式,一旦這樣的記憶體映射到共享它的行程的地址空間,這些行程間資料傳遞不再涉及到內核,換句話說是行程不再通過執行進入內核的系統呼叫來傳遞彼此的資料
共享記憶體并未提供同步機制,在第一個行程結束對共享記憶體的寫操作之前,并無自動機制可以阻止第二個行程開始對它進行讀取,
共享記憶體示意圖

二、共享記憶體原理
每個行程都有行程控制塊(PCB)和地址空間(Addr Space),通過頁表對應,負責虛擬地址與物理地址映射,通過記憶體管理單元(MMU)管理,兩個不同的虛擬地址通過頁表映射到物理空間的同一區域,它們所指向的這塊區域即共享記憶體,
1. 共享記憶體的通信原理

當兩個行程通過頁表將虛擬地址映射到物理地址時,共享記憶體可以被兩個行程同時看到,這樣當一個行程進行寫操作,另一個行程讀操作就可以實作行程間通信,但要確保一個行程在寫的時候不能被讀,所以通過信號量來實作同步與互斥,
共享記憶體實作采用的是參考計數的原理,當行程脫離共享存盤區后,計數器減一,掛架成功時,計數器加一,只有當計數器變為零時,才能被洗掉,當行程終止時,它所附加的共享存盤區都會自動脫離,
2. 共享記憶體資料結構
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 */
__kernel_time_t shm_dtime; /* last detach time */
__kernel_time_t shm_ctime; /* last change time */
__kernel_ipc_pid_t shm_cpid; /* pid of creator */
__kernel_ipc_pid_t shm_lpid; /* pid of last operator */
unsigned short shm_nattch; /* no. of current attaches */
unsigned short shm_unused; /* compatibility */
void *shm_unused2; /* ditto - used by DIPC */
void *shm_unused3; /* unused */
};
3.共享記憶體的建立程序
(1)申請共享記憶體(物理記憶體已經開辟好了);
(2)共享記憶體掛接到地址空間(建立映射關系);
(3)去關聯共享記憶體(修改頁表,取消映射關系);
(4)釋放共享記憶體(記憶體歸還給系統),
三、共享記憶體函式
1.shmget函式
功能:用來創建共享記憶體
原型:
int shmget(key_t key, size_t size, int shmflg);
引數:
key:這個共享記憶體段名字
size:共享記憶體大小
shmflg:由九個權限標志構成,它們的用法和創建檔案時使用的mode模式標志是一樣的
回傳值:成功回傳一個非負整數,即該共享記憶體段的標識碼;失敗回傳-1
2.shmat函式
功能:將共享記憶體段連接到行程地址空間
原型:
void *shmat(int shmid, const void *shmaddr, int shmflg);
引數:
shmid:共享記憶體標識
shmaddr:指定連接的地址
shmflg:它的兩個可能取值是SHM_RND和SHM_RDONLY
回傳值:成功回傳一個指標,指向共享記憶體第一個節;失敗回傳-1
另外:
shmaddr為NULL,核心自動選擇一個地址,
shmaddr不為NULL且shmflg無SHM_RND標記,則以shmaddr為連接地址,
shmaddr不為NULL且shmflg設定了SHM_RND標記,則連接的地址會自動向下調整為SHMLBA整數倍,公式:shmaddr -(shmaddr % SHMLBA),
shmflg=SHM_RDONLY,表示連接操作用來只讀共享記憶體,
3.shmdt函式
功能:將共享記憶體段與當前行程脫離
原型:
int shmdt(const void *shmaddr);
引數:shmaddr: 由shmat所回傳的指標
回傳值:成功回傳0;失敗回傳-1
注意:將共享記憶體段與當前行程脫離不等于洗掉共享記憶體段
4. shmctl函式
功能:用于控制共享記憶體
原型:
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
引數:
shmid:由shmget回傳的共享記憶體標識碼
cmd:將要采取的動作(有三個可取值)
buf:指向一個保存著共享記憶體的模式狀態和訪問權限的資料結構
回傳值:成功回傳0;失敗回傳-1
| 命令 | 說明 |
|---|---|
| IPC_STAT | 把shmid_ds結構中的資料設定為共享記憶體的當前關聯值 |
| IPC_SET | 在行程有足夠的權限的前提下,把共享記憶體當前關聯值設定為shmid_ds資料結構中給出的值 |
| IPC_RMID | 洗掉共享記憶體段 |
三、共享記憶體實體
server通過共享記憶體給client發送資料,、
ftok函式:把一個已經存在的路徑名和一個整數標識得轉換成一個key_t值,稱為IPC鍵
makefile
.PHONY:all
all:client server
client: client.c
gcc -o $@ $^
server: server.c
gcc -o $@ $^
.PHONY:clear
clear:
rm client server
server.c
#include<stdio.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/types.h>
#define SIZE 4096
#define PATHNAME "/home/Zht/Linux/SHM"
#define PROJ_ID 0x66
int main()
{
key_t k = ftok(PATHNAME, PROJ_ID);
if(k < 0){
perror("ftok");
return 1;
}
int shmid = shmget(k, SIZE, IPC_CREAT | IPC_EXCL | 0644); //開辟
if(shmid < 0){
perror("shmget");
return 2;
}
char *mem = shmat(shmid, NULL, 0); //掛接
int i = 0;
while(1)
{
mem[i] = 'A' + i;
i++;
sleep(1);
mem[i] = '\0';
}
shmdt(mem);
//shmctl(shmid, IPC_RMID, NULL); //釋放
return 0;
}
client.c
#include<stdio.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/types.h>
#define SIZE 4096
#define PATHNAME "/home/Zht/Linux/SHM"
#define PROJ_ID 0x66
int main()
{
key_t k = ftok(PATHNAME, PROJ_ID);
if(k < 0){
perror("ftok");
return 1;
}
int shmid = shmget(k, SIZE, IPC_CREAT); //開辟
if(shmid < 0){
perror("shmget");
return 2;
}
char *mem = shmat(shmid, NULL, 0); //掛接
int i = 0;
while(1)
{
printf("server meg# %s\n", mem); //讀取
sleep(1);
}
shmdt(mem);
//shmctl(shmid, IPC_RMID, NULL); //釋放
return 0;
}
結果
運行時

正常接收
掛接也為2

終止后掛接為0,
四、system V訊息佇列
訊息佇列提供了一個從一個行程向另外一個行程發送一塊資料的方法,
每個資料塊都被認為是有一個型別,接收者行程接收的資料塊可以有不同的型別值特性方面,
IPC資源必須洗掉,否則不會自動清除,除非重啟,所以system V IPC資源的生命周期隨內核,
五、system V信號量
信號量主要用于同步和互斥的,
1.行程互斥
由于各行程要求共享資源,而且有些資源需要互斥使用,因此各行程間競爭使用這些資源,行程的這種關系為行程的互斥,
系統中某些資源一次只允許一個行程使用,稱這樣的資源為臨界資源或互斥資源,
行程中涉及到互斥資源的程式段叫臨界區,
IPC資源必須洗掉,否則不會自動清除,除非重啟,所以system V IPC資源的生命周期隨內核,
總結
行程間的通信主要分為管道和system V,管道有可分為匿名管道和命名管道;system V行程間通信包括了共享記憶體、訊息佇列、信號量,兩篇文章對他們進行了介紹,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/354633.html
標籤:其他
上一篇:Linux知識小結
下一篇:從無都有生成一個單鏈表
