共享內(nèi)存
原理與概念
兩個(gè)進(jìn)程的PCB創(chuàng)建虛擬地址空間然后映射到物理內(nèi)存中,每個(gè)進(jìn)程因?yàn)槭仟?dú)立的,所以在物理內(nèi)存中的地址也不同。
那么共享內(nèi)存是怎么做到的呢?
首先先在物理內(nèi)存中申請一塊內(nèi)存。
然后講這塊內(nèi)存通過頁表映射分別映射到這兩個(gè)進(jìn)程的虛擬地址空間內(nèi),讓這兩個(gè)進(jìn)程都能看到這塊內(nèi)存。(這里也稱為進(jìn)程和共享內(nèi)存掛接)
最后如果不想通信了:
取消進(jìn)程和內(nèi)存的映射關(guān)系(去關(guān)聯(lián))
釋放內(nèi)存(釋放共享內(nèi)存)
理解:
a.這里和原本C語言當(dāng)中的maclloc函數(shù)開辟空間不同,我們的目的是要讓兩個(gè)進(jìn)程同時(shí)看到這塊內(nèi)存。
b.進(jìn)程通信的這個(gè)申請一塊共享內(nèi)存是專門設(shè)計(jì)出來的,用來IPC。
c.共享內(nèi)存是一種通信的方式,所有想通信的進(jìn)程都可以用。
d.OS一定可能會存在很多的共享內(nèi)存。
概念就是:通過讓不同進(jìn)程看到同一個(gè)內(nèi)存塊的方式就叫做共享內(nèi)存。
函數(shù)接口的介紹與使用
shmget
創(chuàng)建共享內(nèi)存接口:
首先來看第三個(gè)參數(shù):
這里是通過位圖的方式(二進(jìn)制標(biāo)志位)傳參。
IPC_CREAT 如果不存在,創(chuàng)建,如果存在,就獲取共享內(nèi)存的位置。
IPC_EXCL 這個(gè)選項(xiàng)無法單獨(dú)使用,必須結(jié)合IPC_CREAT使用,一起使用代表的含義是,如果不存在就創(chuàng)建,存在就會返回錯(cuò)誤。(也就是說如果創(chuàng)建成功,他一定是一個(gè)新的共享內(nèi)存——shm)
第二個(gè)參數(shù)是創(chuàng)建shm的大小。
返回值:
如果成功就返回一個(gè)共享內(nèi)存的合法標(biāo)識符,失敗就返回-1。(這個(gè)和文件操作符完全不同,不是一個(gè)體系)
第一個(gè)參數(shù):
這個(gè)是讓多個(gè)進(jìn)程看到同一份shm的關(guān)鍵。能進(jìn)行唯一標(biāo)識。
這個(gè)值是怎么來的呢?
用這個(gè)函數(shù)生成:
將一個(gè)合法路徑(字符串)和字符數(shù)據(jù)通過某種算法組合來進(jìn)行計(jì)算出key值,然后返回key。
失敗了返回-1。
那么,怎么樣才能讓兩個(gè)進(jìn)程看到同一份共享內(nèi)存呢?
在兩個(gè)進(jìn)程中如果傳入到ftok中的兩個(gè)參數(shù)相同,返回的key也相同,其中一個(gè)進(jìn)程通過shmget接口創(chuàng)建共享內(nèi)存,另一個(gè)接口通過shmget接口接收共享內(nèi)存的位置,這樣兩個(gè)進(jìn)程就能看到同一份資源了。
我們要利用接口讓兩個(gè)進(jìn)程實(shí)現(xiàn)通信,首先創(chuàng)建兩個(gè).cc的文件,一個(gè)頭文件.hpp。
因?yàn)閮蓚€(gè)進(jìn)程都要創(chuàng)建/獲取共享內(nèi)存,所以獲取key等等操作在頭文件更方便。
#ifndef _COMM_HPP_
#define _COMM_HPP_
#include<iostream>
#include<cassert>
#include<cstring>
#include<cerrno>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<cstdlib>
#define PATHNAME "."//ftok的第一個(gè)參數(shù),是一個(gè)合法路徑
#define PROJ_IO 0X666//ftok的第二個(gè)參數(shù)
key_t getkey()
{
key_t k = ftok(PATHNAME, PROJ_IO);
if(k < 0)
{
std::cerr << errno << ":" << strerror(errno) << std::endl;
exit(1);
}
return k;
}
#endif
然后來測試一下這個(gè)函數(shù):
兩個(gè)進(jìn)程都調(diào)用這個(gè)函數(shù):
#include"shm.hpp"
int main()
{
key_t k = getkey();
printf("0x%x\n",k);
return 0;
}
運(yùn)行之后我們發(fā)現(xiàn)兩個(gè)進(jìn)程打印的結(jié)果key值都是相同的。
key_t的本質(zhì)就是一個(gè)32位的整數(shù)。
然后再用shmget去創(chuàng)建和獲取共享內(nèi)存。
int getshmhelper(key_t k, int flags)
{
int shmid = shmget(k, MAXSIZE, flags);
if(shmid < 0)
{
std::cerr << errno << ":" << strerror(errno) << std::endl;
exit(2);
}
return shmid;
}
int getshm(key_t k)//獲取共享內(nèi)存
{
return getshmhelper(k, IPC_CREAT);//沒有就創(chuàng)建,有就獲取
}
int createshm(key_t k)//創(chuàng)建共享內(nèi)存
{
return getshmhelper(k, IPC_CREAT | IPC_EXCL | 0600);//沒有創(chuàng)建,有就報(bào)錯(cuò),這里創(chuàng)建內(nèi)存需要給對應(yīng)的權(quán)限
}
我們讓server去創(chuàng)建一個(gè)共享內(nèi)存,client去拿共享內(nèi)存中的數(shù)據(jù)。
這里再次創(chuàng)建共享內(nèi)存會報(bào)錯(cuò)。
那么key的意義是什么呢?
首先清楚,OS一定可能會存在很多共享內(nèi)存,并且本質(zhì)就是申請一塊空間,能進(jìn)行唯一性標(biāo)識最重要。
之前的C語言,malloc開辟n大小的空間的時(shí)候,釋放時(shí)并不需要告訴他釋放多大,自己就知道釋放掉n個(gè)大小的內(nèi)存,其實(shí)這一塊內(nèi)存中OS也要對這塊中間做管理,申請了n個(gè)大小,并不代表就是n個(gè),因?yàn)槔锩孢€有對這塊內(nèi)存的屬性和數(shù)據(jù)左儲存,比如大小,釋放的時(shí)候就回去找這個(gè)大小。
這里共享內(nèi)存也是一樣的,OS要先描述再組織,才能進(jìn)行管理,每次申請一塊共享內(nèi)存,OS還會給這塊共享內(nèi)存申請一個(gè)數(shù)據(jù)結(jié)構(gòu)對象。
所以:共享內(nèi)存 = 物理內(nèi)存快 + 共享內(nèi)存的相關(guān)屬性
OS管理的是對這個(gè)共享內(nèi)存的數(shù)據(jù)結(jié)構(gòu)對象做管理的。
那么在創(chuàng)建共享內(nèi)存的時(shí)候,如何保證共享內(nèi)存在OS中是唯一的呢?答案就是key。
key就像餐廳當(dāng)中的桌號一樣,每個(gè)都具有唯一性。
其中一個(gè)進(jìn)程創(chuàng)建共享內(nèi)存,這塊區(qū)域中有key值,只要另一個(gè)進(jìn)程也看到同一個(gè)key就說明能看到同一塊內(nèi)存。
那么怎么找到key 的位置呢?就在共享內(nèi)存中的數(shù)據(jù)結(jié)構(gòu)中。
struct shm
{
key_t k;
}
也就是說ftok函數(shù)返回的key值其實(shí)就是賦值給共享內(nèi)存數(shù)據(jù)結(jié)構(gòu)中的key值。
這就是創(chuàng)建key的含義,key是要通過shmget設(shè)置進(jìn)入共享內(nèi)存屬性中的,用來表示該共享內(nèi)存在內(nèi)核中的唯一性。
那么用來接收shmget返回值的變量有什么意義呢?
比如說,我們在企業(yè)有自己的員工號,企業(yè)擴(kuò)大的時(shí)候,變動的是員工號,并不影響我們的身份證號,這時(shí)一種解耦的體現(xiàn)。
用來接收shmget返回值的變量和key值互相不干擾。
就像鑰匙和鎖一樣。(fd與inode也是相同的道理)
那么如何查看IPC資源呢?
首先上面的代碼在創(chuàng)建共享內(nèi)存的時(shí)候,明明進(jìn)程已經(jīng)結(jié)束了,但還顯示這個(gè)資源已被占用,因?yàn)楣蚕韮?nèi)存是OS級的,他的生命周期是和OS相同的,要等OS的關(guān)機(jī)才會釋放掉。
這里用 ipcs -m 查看共享內(nèi)存。
想刪除這塊共享內(nèi)存要用 ipcrm -m shmid
這種方法不太好,所以提供了另一個(gè)接口。
shmctl
第一個(gè)參數(shù)就是上面接受創(chuàng)建共享內(nèi)存函數(shù)的返回值,第二個(gè)參數(shù)是選項(xiàng),用來控制這個(gè)函數(shù)做什么,第三個(gè)參數(shù)是一個(gè)數(shù)據(jù)結(jié)構(gòu),就是下面的那個(gè):
返回值是shmid,失敗返回-1。
這個(gè)選項(xiàng)就是刪除掉這段共享內(nèi)存。
void delshm(int shmid)
{
if(shmctl(shmid, IPC_RMID, nullptr) == -1)
{
std::cerr << errno << ":" << strerror(shmid) << std::endl;
exit(3);
}
}
這里誰創(chuàng)建的誰進(jìn)行刪除就可以了。
現(xiàn)在還差一步讓兩個(gè)進(jìn)程與這個(gè)共享內(nèi)存關(guān)聯(lián)。
shmat
第一個(gè)參數(shù)是想和哪一個(gè)共享內(nèi)存關(guān)聯(lián),第二個(gè)參數(shù)是想把這個(gè)共享內(nèi)存映射到地址空間的哪個(gè)地方(不常用),第三個(gè)權(quán)限是讀寫權(quán)限(一般設(shè)置為0)。
返回值是將映射到虛擬地址空間的起始地址位置返回。(等價(jià)于C語言的malloc)
失敗返回-1。
void* attachshm(int shmid)
{
void* p = shmat(shmid, nullptr, 0);
if((long long)p == -1L)//因?yàn)閘inux系統(tǒng)是64位,一個(gè)地址是8個(gè)字節(jié),所以要變成8個(gè)字節(jié)大小的數(shù)據(jù)類型做對比
{
std::cerr << errno << ":" << strerror(errno) << std::endl;
exit(4);
}
return p;
}
這里就代表掛接成功了,這個(gè)共享內(nèi)存掛接了一個(gè)進(jìn)程。
那么如何去關(guān)聯(lián)呢?
shmdt
其實(shí)就是調(diào)用去卸載當(dāng)前進(jìn)程共享內(nèi)存的地虛擬地址空間,參數(shù)就是shmat的返回值。
返回值成功是0,錯(cuò)誤是-1.
void detachshm(void* p)
{
if(shmdt(p) == -1)
{
std::cerr << errno << ":" << strerror(errno) << std::endl;
}
}
然后完善一下另一個(gè)文件中的代碼:
這一份不需要他釋放掉共享內(nèi)存。
這里讓server多休息一會。
通信
然后來完善通信的一下代碼:
#ifndef _COMM_HPP_
#define _COMM_HPP_
#include<iostream>
#include<cassert>
#include<cstring>
#include<cerrno>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<cstdlib>
#include<unistd.h>
#define PATHNAME "."//ftok的第一個(gè)參數(shù),是一個(gè)合法路徑
#define PROJ_IO 0X666//ftok的第二個(gè)參數(shù)
#define MAX_SIZE 4096//共享內(nèi)存的大小
key_t getkey()
{
key_t k = ftok(PATHNAME, PROJ_IO);
if(k < 0)
{
std::cerr << errno << ":" << strerror(errno) << std::endl;
exit(1);
}
return k;
}
int getshmhelper(key_t k, int flags)
{
int shmid = shmget(k, MAX_SIZE, flags);
if(shmid < 0)
{
std::cerr << errno << ":" << strerror(errno) << std::endl;
exit(2);
}
return shmid;
}
int getshm(key_t k)//獲取共享內(nèi)存
{
return getshmhelper(k, IPC_CREAT);//沒有就創(chuàng)建,有就獲取
}
int createshm(key_t k)//創(chuàng)建共享內(nèi)存
{
return getshmhelper(k, IPC_CREAT | IPC_EXCL | 0600);//沒有創(chuàng)建,有就報(bào)錯(cuò),這里創(chuàng)建內(nèi)存需要給對應(yīng)的權(quán)限
}
void delshm(int shmid)
{
if(shmctl(shmid, IPC_RMID, nullptr) == -1)
{
std::cerr << errno << ":" << strerror(shmid) << std::endl;
exit(3);
}
}
void* attachshm(int shmid)
{
void* p = shmat(shmid, nullptr, 0);
if((long long)p == -1L)//因?yàn)閘inux系統(tǒng)是64位,一個(gè)地址是8個(gè)字節(jié),所以要變成8個(gè)字節(jié)大小的數(shù)據(jù)類型做對比
{
std::cerr << errno << ":" << strerror(errno) << std::endl;
exit(4);
}
return p;
}
void detachshm(void* p)
{
if(shmdt(p) == -1)
{
std::cerr << errno << ":" << strerror(errno) << std::endl;
}
}
#endif
#include"shm.hpp"
int main()
{
key_t k = getkey();
printf("0x%x\n",k);
int shmid = getshm(k);//接收共享內(nèi)存
printf("shmid : %d\n", shmid);
char* p = (char*)attachshm(shmid);//關(guān)聯(lián)
printf("attach sucess, address p: %p\n",p);
//使用
const char* str = "hello server, 我是另一個(gè)進(jìn)程,我在和你通信";
pid_t id = getpid();
int count = 0;
while(true)
{
sleep(1);
snprintf(p, MAX_SIZE, "%S[pid:%d][消息編號:%d]", str, id, count++);
}
detachshm(p);//去關(guān)聯(lián)
return 0;
}
#include"shm.hpp"
int main()
{
key_t k = getkey();
printf("0x%x\n",k);
int shmid = createshm(k);//創(chuàng)建共享內(nèi)存
printf("shmid : %d\n", shmid);
char* p = (char*)attachshm(shmid);//關(guān)聯(lián)
printf("attach sucess, address p: %p\n",p);
//使用
while(true)
{
printf("client say: %s\n",p);
sleep(1);
}
detachshm(p);//去關(guān)聯(lián)
sleep(10);
delshm(shmid);//刪除共享內(nèi)存
return 0;
}
共享內(nèi)存的特點(diǎn)
優(yōu)點(diǎn):是所有進(jìn)程通信中速度最快的,并且不像原來管道的那種需要定義一個(gè)buffer來儲存數(shù)據(jù),減少拷貝次數(shù)。
相比較于管道,數(shù)據(jù)傳輸進(jìn)管道需要拷貝一次,數(shù)據(jù)傳出數(shù)據(jù)需要拷貝一次,而共享內(nèi)存不用。
共享內(nèi)存的缺點(diǎn):
不給我們進(jìn)行同步和互斥的操作,也就是沒有對數(shù)據(jù)進(jìn)行任何保護(hù)。沒任何規(guī)定,沒有寫也讀,寫到一半也會去讀,這種情況就要用信號量去處理了。
那么如何實(shí)現(xiàn)呢?
寫完,通知讀端讀取
沒通知的時(shí)候讓server等待
如果不通過信號量,可以用兩個(gè)匿名管道進(jìn)行操作,思路:
兩個(gè)進(jìn)程寫和讀之前遵守管道的規(guī)則,沒有不能讀,滿了不能寫等等。
共享內(nèi)存的內(nèi)核結(jié)構(gòu)
之前在介紹shmctl接口中,文檔已經(jīng)顯示了共享內(nèi)存的數(shù)據(jù)結(jié)構(gòu)了:
那么我們怎么拿到這些屬性呢?通過這個(gè)選項(xiàng),來拷貝內(nèi)核的數(shù)據(jù)結(jié)構(gòu)然后傳出來。
其中key是在第一個(gè)數(shù)據(jù)結(jié)構(gòu)的第一個(gè)成員的數(shù)據(jù)結(jié)構(gòu)當(dāng)中,這相當(dāng)于又做了一層封裝。
這里還有一個(gè)重點(diǎn),如果我們將共享內(nèi)存的大小改成4097會怎么樣?
那么顯示這塊內(nèi)存的數(shù)據(jù)結(jié)構(gòu)是4097的大小,但是實(shí)際物理內(nèi)存以你為是按照每次最少開辟4KB大小算的(內(nèi)存劃分內(nèi)存塊的基本單位),所以一般都是開辟4KB的整數(shù)倍,這里顯示是4097只是因?yàn)樗菙?shù)據(jù)結(jié)構(gòu),實(shí)際上多出了4KB-1的空間大小,內(nèi)核這里會給我們向上取整。
這里要按照數(shù)據(jù)結(jié)構(gòu)的大小才能算是我們能用的大小,這里內(nèi)核給的和能用多少是兩碼事。
system V消息隊(duì)列(了解)
消息隊(duì)列提供了一個(gè)從一個(gè)進(jìn)程向另外一個(gè)進(jìn)程發(fā)送一塊數(shù)據(jù)的方法。
每個(gè)數(shù)據(jù)塊都被認(rèn)為是有一個(gè)類型,接收者進(jìn)程接收的數(shù)據(jù)塊可以有不同的類型值特性方面。
IPC資源必須刪除,否則不會自動清除,除非重啟,所以system V IPC資源的生命周期隨內(nèi)核。
用這個(gè)接口可以獲取消息隊(duì)列:
返回值是創(chuàng)建好的消息隊(duì)列的標(biāo)識符。
下面這個(gè)是消除消息隊(duì)列。
這是消息隊(duì)列的數(shù)據(jù)結(jié)構(gòu)。
也可以理解為是一個(gè)鏈?zhǔn)浇Y(jié)構(gòu)。
想查看消息隊(duì)列用:ipcs -q
system V——初識信號量
想查看信號量用:ipcs -s
信號量的預(yù)備概念
在了解信號量之前先了解這些概念:
信號量是什么?本質(zhì)是一個(gè)計(jì)數(shù)器,通常用來表示公共資源中,資源數(shù)量的多少問題的。
公共資源:被多個(gè)進(jìn)程可以同時(shí)訪問的資源。
訪問沒有保護(hù)的公共資源:會導(dǎo)致數(shù)據(jù)不一致的問題,比如正在寫的時(shí)候,另一個(gè)進(jìn)程已經(jīng)讀了。
我們未來將被保護(hù)起來的公共資源:臨界資源,有大部分的資源是獨(dú)立的。
資源是什么:內(nèi)存,文件,網(wǎng)絡(luò)等。只要是被使用的就算。那么如何被使用呢?一定是該進(jìn)程有對應(yīng)的代碼來訪問這部分資源,在訪問的時(shí)候會被保護(hù)起來,這部分代碼被稱為臨界區(qū),其他沒有訪問這部分公共資源的叫做非臨界區(qū)。
例如:
紅框這里是在打印p這個(gè)共享內(nèi)存的內(nèi)容,這個(gè)就是臨界區(qū),其他代碼就是非臨界區(qū)。
那么如何保護(hù)呢?同步&&互斥:
這里先了解什么是互斥,其實(shí)就是當(dāng)有兩個(gè)進(jìn)程想訪問一分公共資源時(shí),不能兩個(gè)同時(shí)一起訪問,要等一個(gè)訪問完之后另一個(gè)才能進(jìn)行訪問。
原子性:要么不做,要么就做完。這個(gè)叫做原子性。比如,A給B微信轉(zhuǎn)錢,A 轉(zhuǎn)了 B 50,但是50沒有發(fā)送到B的賬戶里面,反而A的賬戶扣了50,這樣是很不合理的,所以這里就要用原子性,要么轉(zhuǎn)錢轉(zhuǎn)過去A賬戶扣50,要么轉(zhuǎn)錢失敗A賬戶一分都不少,只有這兩種結(jié)果。
信號量和這些有什么關(guān)系呢信號量主要就是完成同步互斥和原子性的!
理解信號量
那么在深入了解一下信號量是什么,信號量雖然是一個(gè)計(jì)數(shù)器,但是不可能是一個(gè)進(jìn)程的全局變量。
假設(shè):
信號量是售票的處,他有100張票。
公共資源是電影院的座位,有100個(gè)。
那么如果我買完票了,座位號是1,我沒有坐到這個(gè)位置上,但是這個(gè)位置也是屬于我的。
也就是說我相當(dāng)于對這個(gè)1號位置進(jìn)行了預(yù)定,也就是說我們申請資源的時(shí)候要進(jìn)行預(yù)定。
并且,座位只有100張,不能賣100張以上的票。
那么我們定義票數(shù)是count = 100;
賣出去一張是count–,如果if(count == 0) 就不賣了;
那么你公共資源可以分為兩種:
1.作為一個(gè)整體使用。(管道)
2.劃分成為一個(gè)一個(gè)的資源子部分。(食堂打飯不可能只開放一個(gè)窗口打飯,一個(gè)人打完另一個(gè)人進(jìn),這樣是不行的,所以要將食堂分成多個(gè)窗口打飯)
那么如果買到票了,電影院一定讓你進(jìn)入,買不到票電影院不會讓你進(jìn)入,這就屬于一種保護(hù)。
也就是對于臨界資源進(jìn)行的一種保護(hù),這就是信號量。
那么信號量–叫做預(yù)定資源,++就是釋放資源。
也就是說在申請公共資源的時(shí)候,所有進(jìn)程都要通過信號量申請,那么前提是所有進(jìn)程看到的都是同一個(gè)信號量,也就是說信號量本身就是一個(gè)公共資源,那么信號量如何確保自己的安全呢?
上面說了,- - 是預(yù)定資源++是釋放資源,這些操作是讓這個(gè)信號量變化的途徑,這里信號量中的這兩個(gè)操作是原子性的。
預(yù)定資源是P操作,釋放資源是V操作。這就是PV操作。
也就是說信號量在system V版本中同時(shí)被多個(gè)進(jìn)程看到,必須匹配兩個(gè)操作,一個(gè)是P操作,一個(gè)是V操作。
那么如果一個(gè)信號量初始值為1是什么意思呢?
這就說明這個(gè)公共資源是一個(gè)整體資源了。
這個(gè)也叫做二元信號量,主要提供互斥作用的。
信號量的接口與結(jié)構(gòu)
申請信號量。
第二個(gè)參數(shù)是申請幾個(gè)信號量,第三個(gè)參數(shù)依舊是選項(xiàng)。
返回值是返回一個(gè)信號量的集合。
如果不想用某個(gè)信號量了,用這個(gè)接口:
第一個(gè)參數(shù)是信號量對應(yīng)的id,第二個(gè)參數(shù)是信號量的下標(biāo)(第九個(gè)就填9,不想填就填0),第三個(gè)參數(shù)是選項(xiàng)了:
很多個(gè),不一一列舉了,也可以去獲取信號量的信息。
信號量的數(shù)據(jù)結(jié)構(gòu):
那么怎么對信號量進(jìn)行PV操作呢?
第一個(gè)參數(shù)是指定的信號量,第二個(gè)參數(shù)是選項(xiàng),1是++,-1是- -。
第三個(gè)參數(shù)是代表要第二個(gè)參數(shù)的結(jié)構(gòu)體有多少個(gè),假如說之前申請了10個(gè)信號量,那么這里填寫10,然后就可以寫一個(gè)第二個(gè)參數(shù)類型的數(shù)組里面有10個(gè)這種類型的數(shù)據(jù),對這10個(gè)信號量集合做PV操作。(這就像買電影票可以買很多張不同的電影票一樣)
IPC資源的組織方式
這里其實(shí)我們已經(jīng)發(fā)現(xiàn)了,共享內(nèi)存的數(shù)據(jù)結(jié)構(gòu),消息隊(duì)列的數(shù)據(jù)結(jié)構(gòu),信號量的數(shù)據(jù)結(jié)構(gòu),他們的接口相似度非常高!
這就說明,他們屬于system V標(biāo)準(zhǔn)的進(jìn)程通信。
他們的第一個(gè)成員,全都是這一種結(jié)構(gòu):
我們可以用一個(gè)指針數(shù)組來組織這個(gè)數(shù)據(jù)結(jié)構(gòu):
我們只要將這三個(gè)不同的數(shù)據(jù)結(jié)構(gòu)中第一個(gè)成員放進(jìn)這個(gè)數(shù)組中就可以了。文章來源:http://www.zghlxwxcb.cn/news/detail-429653.html
因?yàn)?,結(jié)構(gòu)體第一個(gè)成員的地址是和這個(gè)結(jié)構(gòu)體對象本身的地址是相同的。
也就是說如果未來想訪問共享內(nèi)存的數(shù)據(jù)結(jié)構(gòu),直接將perms數(shù)組中第一個(gè)元素取出來,然后強(qiáng)制轉(zhuǎn)換成共享內(nèi)存數(shù)據(jù)結(jié)構(gòu)的構(gòu)造體就可以了!
C++多態(tài)就是通過這個(gè)思維創(chuàng)建出來的!文章來源地址http://www.zghlxwxcb.cn/news/detail-429653.html
到了這里,關(guān)于Linux進(jìn)程通信——共享內(nèi)存的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!