最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Linux共享內(nèi)存原理及分析

 更新時間:2025年10月09日 09:10:39   作者:每天敲200行代碼  
文章介紹了共享內(nèi)存作為進(jìn)程通信方式,通過物理內(nèi)存映射實現(xiàn)進(jìn)程間共享資源,其核心步驟為申請內(nèi)存、掛接虛擬地址、去關(guān)聯(lián)釋放,需用戶指定key值確保唯一性,操作系統(tǒng)管理其生命周期,共享內(nèi)存速度快但需自行維護(hù)同步機(jī)制

一、前言

我們之前提到過,進(jìn)程通信是讓兩個不同的進(jìn)程看到同一份資源,所以我們給大家講解了匿名管道和命名管道。

今天我們還有一種方式兩個不同的進(jìn)程看到同一份資源。

那就是共享內(nèi)存

二、共享內(nèi)存原理

我們先來看這張圖,我們在物理內(nèi)存創(chuàng)建一個共享區(qū),我們再讓兩個不同的進(jìn)程通過頁表分別映射到對應(yīng)的共享區(qū)里,然后返回虛擬地址的起始地址。

這就是共享內(nèi)存,我們總結(jié)分為三步

  • 申請內(nèi)存。
  • 將該內(nèi)存掛接到進(jìn)程地址空間的共享區(qū)。
  •  返回虛擬地址首地址。

以上我們就創(chuàng)建好共享內(nèi)存了,那我們該如何釋放共享內(nèi)存呢?

去關(guān)聯(lián),我們通過系統(tǒng)調(diào)用釋放共享內(nèi)存,這個系統(tǒng)調(diào)用由操作系統(tǒng)提供,并且進(jìn)程調(diào)用系統(tǒng)調(diào)用是由操作系統(tǒng)操作。

我們可能會有很多個共享內(nèi)存,那操作系統(tǒng)要不要管理所有的共享內(nèi)存呢?

  • 當(dāng)然要,還是六個字——“先描述,后組織”。
  • 由內(nèi)核結(jié)構(gòu)體描述共享內(nèi)存。

接下來我們通過寫一些代碼了解該原理,在寫代碼之前我們要先了解一些接口。

三、代碼

1、系統(tǒng)調(diào)用接口

man shmget  
int shmget(key_t key, size_t size, int shmflg);

我們先把這個key放一放最后再講

這個size_t size是創(chuàng)建共享內(nèi)存的大小,單位是字節(jié)。 

shmflg我們知道,我們這個共享內(nèi)存創(chuàng)建出來了以后,就不需要再次創(chuàng)建了,只需要獲取即可

所以就注定了我們需要如何創(chuàng)建,如何獲取。如果需要關(guān)注的選項就是下面兩個。

  • IPC_CREAT(單獨使用)的意思是創(chuàng)建一個共享內(nèi)存,如果這個共享內(nèi)存存在,直接獲取,如果不存在就創(chuàng)建并返回他
  • IPC_CREAT | IPC_EXCL(兩個一起使用):如果申請的共享額你存不存在,就創(chuàng)建,如果存在就出錯返回。它可以確保如果我們申請成功了,這個共享內(nèi)存一定是一個新的
  • IPC_EXCL不單獨使用

對于它的返回值

如果成功,他會返回一個共享內(nèi)存的標(biāo)識,如果失敗,返回-1 (問題二)

這里我想問一下大家?我們怎么判斷兩個進(jìn)程是不是看到同一份資源呢?

這就跟key值有關(guān)了。

只要兩個進(jìn)程拿到同一個key,就能看到同一份共享內(nèi)存。

因為它在內(nèi)核中具有唯一性,能夠讓不同的進(jìn)程進(jìn)行唯一性標(biāo)識。

第一個進(jìn)程可以通過key創(chuàng)建共享內(nèi)存,第二個進(jìn)程只需要通過拿著同一個key就可以和第一個進(jìn)程看到同一個共享內(nèi)存!

那么問題來了,為什么這個key具有唯一性呢?

這里先給大家介紹另一個接口

man ftok
key_t ftok(const char *pathname, int proj_id);

其實這是一套算法,把pathname和proj_id進(jìn)行數(shù)值運算,最后得到這個key值,返回這個key。

pathname和proj_id是由用戶自由指定的,最后形成這個key。

因為同一個函數(shù)中,使用同一個參數(shù)可以產(chǎn)生同一個key。我們這就可以確保兩個進(jìn)程具有一樣的key了,這就是為什么key具有唯一性。

那為什么key不由操作系統(tǒng)創(chuàng)建呢?而是由用戶

因為操作系統(tǒng)并不知道是哪兩個進(jìn)程進(jìn)行通信,哪幾個進(jìn)程通信由用戶決定!

創(chuàng)建好的共享內(nèi)存中,key在哪呢?

 key在共享內(nèi)存的描述對象中。

這個接下來在寫代碼的時候給大家具體描述

2、創(chuàng)建共享內(nèi)存

我們先創(chuàng)建一個共享內(nèi)存

comm.hpp(這里我們直接用了上節(jié)課講的日志系統(tǒng))

#include "log.hpp"
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/ipc.h>
#include <sys/shm.h>

#include <cstring>

const string pathname ="/home/cyp";
const int proj_id = 0x6667;
const int size = 4096;
Log log;

key_t Getkey()
{
   key_t key = ftok(pathname.c_str(),proj_id);
   if(key < 0)
   {
    log.logmessage(Fatal,"ftok error:%s",strerror(errno));
    exit(1);
   }
   log.logmessage(Info,"key creat success:%d",key);
   return key;
}
int GetShareMeHeler(int flag)
{
   key_t key=Getkey();
   int shmid = shmget(key,size,flag);
   if(shmid==-1)
   {
      log.logmessage(Fatal,"shmget error:%s",strerror(errno));
      exit(2);
   }
   log.logmessage(Info,"creat success:%d",shmid);
   return shmid;

}

processa.cc

#include "comm.hpp"

int main()
{
    int shmid = GetShareMeHeler(IPC_CREAT|IPC_EXCL);
    log.logmessage(Info,"process quit..");
    return 0;
}

結(jié)果如下

這里我們用ipcs -m能查看共享內(nèi)存資源,我們能看到共享內(nèi)存被創(chuàng)建出來了。

key VS shmid

  •  key是操作系統(tǒng)內(nèi)標(biāo)定的唯一性。
  • shmid只有在進(jìn)程內(nèi)表示資源的唯一性。

從上述運行結(jié)果看,進(jìn)程退出了,我們用該命令還能查看到我們在該進(jìn)程創(chuàng)建的共享內(nèi)存。

結(jié)論 :共享內(nèi)存的生命周期是隨內(nèi)核的,用戶不主動關(guān)閉共享內(nèi)存,共享內(nèi)存會一直存在。

如果我們想刪掉共享內(nèi)存的話,我們可以用這個指令

iprm -m 刪除共享內(nèi)存資源,后面接著共享內(nèi)存的標(biāo)識符

查看共享內(nèi)存,有幾個我們不認(rèn)識,perms是權(quán)限,它其實也是一個文件,我們可以為他設(shè)置對應(yīng)的權(quán)限。nattch是關(guān)聯(lián)的意思,意思是當(dāng)前有幾個進(jìn)程與這塊共享內(nèi)存是關(guān)聯(lián)的

那么我們該怎么設(shè)置權(quán)限呢?

接下來我們創(chuàng)建共享內(nèi)存接口,一個是創(chuàng)建,一個是獲取。

3、將進(jìn)程掛接到共享內(nèi)存

這里我們給大家介紹一個接口

man shmdt
void *shmat(int shmid, const void *shmaddr, int shmflg);

  • 第一個參數(shù)好說,我們知道就是我們剛剛的共享內(nèi)存的shmid
  • 第二個參數(shù)shmaddr,代表的含義是我們想將共享內(nèi)存掛接到哪個位置。即共享區(qū)的哪個位置,我們一般可以設(shè)置為nullptr,讓系統(tǒng)去決定掛到哪里去了
  • 第三個參數(shù)就是該共享內(nèi)存的權(quán)限,比如只讀等等,當(dāng)然我們也可以設(shè)置為0,就是按照默認(rèn)的來
  • 這個返回值void*比較像我們以前的malloc,malloc得到是一塊虛擬地址,只有當(dāng)讀寫的時候才發(fā)生缺頁中斷,才申請內(nèi)存

我們寫一份代碼將進(jìn)程掛接到該共享內(nèi)存上。

結(jié)果如下:

4、去關(guān)聯(lián)

這里給大家再介紹一個接口

man shmdt 
int shmdt(const void *shmaddr);

這里的shmaddr是我們在掛接的時候返回強轉(zhuǎn)的變量。

 這個接口是比較類似于之前free接口的

那么我們這個是怎么知道我們要釋放多少呢?

所以這里一定隱藏著我們沒有看到的數(shù)據(jù)。malloc也是一樣的

malloc其實會比我們要申請的內(nèi)存多一點點的。用于存儲一些我們看不到的數(shù)據(jù)。所以malloc其實更適合用于申請大空間,因為這樣影響比較小。

我們一般把這些多申請的空間叫做cookie。

這個接口的返回值是成功為0,失敗為-1

5、釋放共享內(nèi)存

如果我們每次運行這個進(jìn)程的時候,總會報錯,這個共享內(nèi)存已經(jīng)存在,那么我們有沒有什么辦法能讓這個共享內(nèi)存隨著我們的進(jìn)程一起釋放掉呢?

man shmctl
int shmctl(int shmid, int cmd, struct shmid_ds *buf);

  • 第一個參數(shù)我們還是比較清楚的就是共享內(nèi)存的id
  • 第二個參數(shù)是我們控制這個共享內(nèi)存的方法

我們目前只關(guān)心這個,它的作用是將共享內(nèi)存標(biāo)記為被刪除的。而我們刪除的時候是不關(guān)心它的屬性的,所以屬性直接設(shè)置為nullptr

對于返回值,成功為0,失敗為-1

  • 第三個參數(shù)就是這樣一個結(jié)構(gòu)體

這些就是一些屬性。這個結(jié)構(gòu)體里面的屬性是我們內(nèi)核當(dāng)中管理共享內(nèi)存的一個子集。也就是可以獲取共享內(nèi)存里面的屬性

6、兩個進(jìn)程通過共享內(nèi)存通信

  • processa進(jìn)程接收信息

  • processb進(jìn)程發(fā)送消息

 shmaddr指定共享內(nèi)存連接到進(jìn)程地址空間中的哪個位置。如果設(shè)置為NULL,系統(tǒng)會自動選擇一個合適的(隨機(jī)的)地址。

我們之前強轉(zhuǎn)了shmaddr返回了它的地址,我們就能通過它的地址進(jìn)行通信。

結(jié)果如下:

  • 它不像管道,沒有數(shù)據(jù)寫入,讀端就會堵塞。
  • 共享內(nèi)存不管寫不寫入,我會一直讀。

當(dāng)寫端進(jìn)程執(zhí)行。 

這里我們存在一個問題,當(dāng)我們又寫入又讀,不會發(fā)生錯亂錯誤嗎?

會,所以我們要用管道去維護(hù)它。

  • 在我們的頭文件里增加一個類

  • 在processa里增加管道代碼

  • processb增加向管道寫入代碼

運行結(jié)果如下:

  • 寫入端還沒寫,讀取端阻塞

  • 通信成功

 

四、共享內(nèi)存特點

  • 共享內(nèi)存沒有同步互斥的保護(hù)機(jī)制
  • 共享內(nèi)存是隨意進(jìn)程通信中,速度最快的,因為拷貝少
  • 共享內(nèi)存內(nèi)部數(shù)據(jù),由用戶自己維護(hù) 

五、共享內(nèi)存的屬性

如下所示,是我們前面所提及的共享內(nèi)存的一些屬性

在第一個結(jié)構(gòu)體中,最重要的字段是第一個shm_perm,這個還是一個結(jié)構(gòu)體,也就是下面的這個。其他的字段后面都有解釋

在這個第二個結(jié)構(gòu)體中,第一個就是key。所以我們應(yīng)用層中生成的key,最后一定會被寫入到內(nèi)核中。里面的這個mode就是共享內(nèi)存的權(quán)限問題

我們可以直接去看看這些屬性

先看看shmctrl接口的控制方法

我們創(chuàng)建了共享內(nèi)存屬性的結(jié)構(gòu)體 

運行結(jié)果如下:

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • centos查找已安裝的jdk路徑的方法

    centos查找已安裝的jdk路徑的方法

    本篇文章主要介紹了centos查找已安裝的jdk路徑的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-10-10
  • Kafka使用入門教程

    Kafka使用入門教程

    Kafka是一個分布式的、可分區(qū)的、可復(fù)制的消息系統(tǒng)。它提供了普通消息系統(tǒng)的功能,但具有自己獨特的設(shè)計。這個獨特的設(shè)計是什么樣的呢
    2015-12-12
  • Linux操作系統(tǒng)的概述與簡介

    Linux操作系統(tǒng)的概述與簡介

    這篇文章概括描述了什么是操作系統(tǒng),Linux的起源,Linux基本特性和Linux的應(yīng)用,希望通過這篇文章可以讓你對Linux操作系統(tǒng)有一個更好的了解
    2021-06-06
  • CentOS7 下安裝telnet服務(wù)的實現(xiàn)方法

    CentOS7 下安裝telnet服務(wù)的實現(xiàn)方法

    這篇文章主要介紹了CentOS7 下安裝telnet服務(wù)的實現(xiàn)方法的相關(guān)資料,希望通過本文能幫助到大家,讓大家實現(xiàn)這樣功能的方法,需要的朋友可以參考下
    2017-10-10
  • Linux環(huán)境實現(xiàn)替換jar包中class文件

    Linux環(huán)境實現(xiàn)替換jar包中class文件

    文章介紹了如何通過替換class文件來避免重復(fù)打包的問題,具體步驟包括查找目標(biāo)文件目錄、解壓目標(biāo)文件、替換已解壓文件、替換jar包文件等
    2025-11-11
  • CentOS7配置SSH遠(yuǎn)程登錄全過程

    CentOS7配置SSH遠(yuǎn)程登錄全過程

    本文詳細(xì)介紹了如何在CentOS和Windows 11之間配置網(wǎng)絡(luò)連接,并在CentOS上安裝和配置SSH服務(wù),文章還涵蓋了配置防火墻和測試SSH連接的步驟
    2026-01-01
  • Linux一次性計劃任務(wù)at命令使用詳解

    Linux一次性計劃任務(wù)at命令使用詳解

    大家好,本篇文章主要講的是Linux一次性計劃任務(wù)at命令使用詳解,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽
    2021-12-12
  • PHP程序員玩轉(zhuǎn)Linux系列 Nginx中的HTTPS詳解

    PHP程序員玩轉(zhuǎn)Linux系列 Nginx中的HTTPS詳解

    這篇文章主要為大家詳細(xì)介紹了PHP程序員玩轉(zhuǎn)Linux系列文章,MySQL備份還原教程,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • Linux守護(hù)進(jìn)程的啟動方法

    Linux守護(hù)進(jìn)程的啟動方法

    這篇文章主要為大家詳細(xì)介紹了Linux守護(hù)進(jìn)程的啟動方法,本文介紹如何將一個 Web 應(yīng)用,啟動為守護(hù)進(jìn)程,感興趣的小伙伴們可以參考一下
    2016-02-02
  • CentOS服務(wù)器平臺搭建mysql主從復(fù)制與讀寫分離的方法

    CentOS服務(wù)器平臺搭建mysql主從復(fù)制與讀寫分離的方法

    這篇文章主要介紹了CentOS服務(wù)器平臺搭建mysql主從復(fù)制與讀寫分離的方法,結(jié)合實例形式較為詳細(xì)的分析了CentOS平臺搭建mysql主從復(fù)制與讀寫分離的步驟、設(shè)置方法、相關(guān)操作技巧與注意事項,需要的朋友可以參考下
    2018-04-04

最新評論

佳木斯市| 蕲春县| 万载县| 车险| 永安市| 茶陵县| 忻州市| 枞阳县| 虞城县| 黎川县| 逊克县| 贵溪市| 秀山| 社会| 报价| 隆安县| 瑞金市| 五大连池市| 余干县| 望江县| 文山县| 东城区| 淅川县| 彰化县| 阜康市| 德庆县| 昌黎县| 莱州市| 称多县| 鄂温| 合江县| 麻阳| 庆安县| 五莲县| 且末县| 来安县| 临澧县| 林西县| 驻马店市| 木里| 霍州市|