Linux進程通信 | 共享內(nèi)存

一摔桦、共享內(nèi)存是什么

在Linux系統(tǒng)中,共享內(nèi)存是一種IPC(進程間通信)方式承疲,它可以讓多個進程在物理內(nèi)存中共享一段內(nèi)存區(qū)域邻耕。

這種共享內(nèi)存區(qū)域被映射到多個進程的虛擬地址空間中,使得多個進程可以直接訪問同一段物理內(nèi)存區(qū)域中的數(shù)據(jù)燕鸽,從而實現(xiàn)進程間的高速數(shù)據(jù)交換和通信兄世。

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

共享內(nèi)存基于內(nèi)核的支持啊研。在共享內(nèi)存中御滩,內(nèi)核維護了一塊物理內(nèi)存區(qū)域,并將其映射到多個進程的虛擬地址空間中党远。每個進程都可以使用指針來訪問共享內(nèi)存區(qū)域中的數(shù)據(jù)削解,就像它們訪問自己的內(nèi)存一樣。

<img src="https://s2.loli.net/2023/03/18/MpBHsE23jhbCkw1.png" alt="使用共享內(nèi)存示例" style="zoom: 25%;" />

三沟娱、共享內(nèi)存的使用方法

相關函數(shù)介紹

shmget函數(shù)

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

用于創(chuàng)建或打開一個共享內(nèi)存區(qū)段氛驮,具體參數(shù)如下:

參數(shù) 類型 說明
key key_t 共享內(nèi)存區(qū)段的關鍵字,用于在多個進程間標識同一個共享內(nèi)存區(qū)段济似。
size size_t 共享內(nèi)存區(qū)段的大小矫废,以字節(jié)為單位。
shmflg int 共享內(nèi)存區(qū)段的訪問權(quán)限和行為屬性砰蠢。

函數(shù)返回值為共享內(nèi)存區(qū)段的標識符 shmid蓖扑,用于標識已創(chuàng)建或已打開的共享內(nèi)存區(qū)段。

shmat函數(shù)

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

用于將共享內(nèi)存區(qū)段連接到當前進程的地址空間台舱,具體參數(shù)如下:

參數(shù) 類型 說明
shmid int 共享內(nèi)存區(qū)段的標識符律杠,用于標識已創(chuàng)建或已打開的共享內(nèi)存區(qū)段。
shmaddr const void* 共享內(nèi)存區(qū)段連接到當前進程地址空間的起始地址,如果為 NULL柜去,則由系統(tǒng)自動選擇一個地址灰嫉。
shmflg int 標志參數(shù),指定共享內(nèi)存區(qū)段的訪問權(quán)限和行為屬性诡蜓。

函數(shù)返回值為共享內(nèi)存區(qū)段連接到當前進程地址空間的起始地址,即指向共享內(nèi)存區(qū)段的指針胰挑。

shmdt函數(shù)

int shmdt(const void *shmaddr);

用于斷開進程與共享內(nèi)存區(qū)段的連接蔓罚,具體參數(shù)如下:

參數(shù) 類型 說明
shmaddr const void* 共享內(nèi)存區(qū)段連接到當前進程地址空間的起始地址。

函數(shù)返回值為 0 表示成功瞻颂,-1 表示失敗豺谈。

shmctl函數(shù)

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

用于控制共享內(nèi)存區(qū)段的行為,如刪除贡这、獲取茬末、設置共享內(nèi)存區(qū)段的屬性等,具體參數(shù)如下:

參數(shù) 類型 說明
shmid int 共享內(nèi)存區(qū)段的標識符盖矫,用于標識已創(chuàng)建或已打開的共享內(nèi)存區(qū)段丽惭。
cmd int 控制命令,指定對共享內(nèi)存區(qū)段的操作類型辈双。
buf struct shmid_ds* 指向共享內(nèi)存區(qū)段屬性結(jié)構(gòu)體的指針责掏,用于獲取或設置共享內(nèi)存區(qū)段的屬性。

常用的cmd參數(shù)包括:

  • IPC_STAT:獲取共享內(nèi)存的狀態(tài)信息湃望,并將該信息存儲在buf參數(shù)指向的結(jié)構(gòu)體中换衬。
  • IPC_SET:設置共享內(nèi)存的狀態(tài)信息,buf參數(shù)指向要設置的新值证芭。
  • IPC_RMID:刪除共享內(nèi)存瞳浦。

函數(shù)返回值為操作成功返回 0,失敗返回 -1废士。

實例演示

以下是一個示例代碼叫潦,其中一個程序用于寫入共享內(nèi)存,另一個程序用于讀取共享內(nèi)存官硝。

寫入程序

/* write.c */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/shm.h>
#include <string.h>

#define SHM_SIZE 1024

int main()
{
    int shmid;
    char *shmaddr;
    char write_buf[SHM_SIZE];

    // 創(chuàng)建共享內(nèi)存段
    shmid = shmget((key_t)1234, SHM_SIZE, 0666|IPC_CREAT);
    if (shmid == -1) {
        perror("shmget failed");
        exit(EXIT_FAILURE);
    }

    // 將共享內(nèi)存段連接到當前進程
    shmaddr = (char*)shmat(shmid, 0, 0);
    if (shmaddr == (void*)-1) {
        perror("shmat failed");
        exit(EXIT_FAILURE);
    }

    // 從標準輸入讀取數(shù)據(jù)并將其寫入共享內(nèi)存
    while(1) {
        fgets(write_buf, SHM_SIZE, stdin);
        strncpy(shmaddr, write_buf, SHM_SIZE);
        if (strncmp(write_buf, "exit", 4) == 0) {
            break;
        }
    }

    // 斷開共享內(nèi)存連接
    if (shmdt(shmaddr) == -1) {
        perror("shmdt failed");
        exit(EXIT_FAILURE);
    }

    // 刪除共享內(nèi)存段
    if (shmctl(shmid, IPC_RMID, 0) == -1) {
        perror("shmctl failed");
        exit(EXIT_FAILURE);
    }
    
    printf("write exit\n");

    return 0;
}

讀取程序

/* read.c */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/shm.h>
#include <string.h>

#define SHM_SIZE 1024

int main()
{
    int shmid;
    char *shmaddr;
    char read_buf[SHM_SIZE];

    // 獲取共享內(nèi)存段
    shmid = shmget((key_t)1234, SHM_SIZE, 0666|IPC_CREAT);
    if (shmid == -1) {
        perror("shmget failed");
        exit(EXIT_FAILURE);
    }

    // 將共享內(nèi)存段連接到當前進程
    shmaddr = (char*)shmat(shmid, 0, 0);
    if (shmaddr == (void*)-1) {
        perror("shmat failed");
        exit(EXIT_FAILURE);
    }

    // 從共享內(nèi)存讀取數(shù)據(jù)并輸出到標準輸出
    while(1) {
        strncpy(read_buf, shmaddr, SHM_SIZE);
        printf("Received message: %s\n", read_buf);
        if (strncmp(read_buf, "exit", 4) == 0) {
            printf("Received exit\n");
            break;
        }
        sleep(1);
    }

    // 斷開共享內(nèi)存連接
    if (shmdt(shmaddr) == -1) {
        perror("shmdt failed");
        exit(EXIT_FAILURE);
    }

    printf("read exit\n");
    
    return 0;
}
  • 編譯這兩個程序
gcc -o write write.c
gcc -o read read.c

在一個終端窗口中運行write, 輸入消息诅挑,在另一個終端窗口中運行read,查看消息泛源。

要退出程序拔妥,則在運行write的終端窗口中鍵入"exit",效果如下:

共享內(nèi)存讀寫

四达箍、 共享內(nèi)存的注意事項

  • 使用共享內(nèi)存需要注意以下幾點:
  1. 同步問題:由于多個進程可以同時訪問共享內(nèi)存没龙,因此必須要使用同步機制來保證數(shù)據(jù)的一致性和正確性。
  2. 內(nèi)存泄漏:如果一個進程崩潰或者沒有及時解除共享內(nèi)存映射,就有可能導致內(nèi)存泄漏的問題硬纤。
  3. 安全問題:共享內(nèi)存是多個進程共享的解滓,因此必須要注意數(shù)據(jù)的安全性和隱私性,避免敏感數(shù)據(jù)泄露筝家。

五洼裤、 共享內(nèi)存的使用技巧

  • 以下是一些共享內(nèi)存的使用技巧:
  1. 分配內(nèi)存時使用 shmget() 系統(tǒng)調(diào)用中的 IPC_PRIVATE 標記,可以確保共享內(nèi)存的鍵值在系統(tǒng)中是唯一的溪王,避免沖突和安全問題腮鞍。
  2. 在讀寫共享內(nèi)存之前,使用信號量或互斥鎖等同步機制來保證數(shù)據(jù)的一致性和正確性莹菱。
  3. 在使用共享內(nèi)存時移国,可以將共享內(nèi)存區(qū)域按照固定大小進行分塊,避免多個進程同時訪問同一塊內(nèi)存區(qū)域的沖突道伟。

小結(jié)

共享內(nèi)存是一種高效迹缀、靈活、方便的進程間通信方式蜜徽,可以用于在多個進程之間共享大量數(shù)據(jù)祝懂。

使用共享內(nèi)存需要注意同步、安全和內(nèi)存泄漏等問題拘鞋,可以使用信號量嫂易、互斥鎖等同步機制來保證數(shù)據(jù)的正確性。

以上掐禁,如果覺得對你有幫助怜械,點個贊再走吧,這樣@知微之見也有更新下去的動力傅事!

也歡迎私信我缕允,一起交流!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蹭越,一起剝皮案震驚了整個濱河市障本,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌响鹃,老刑警劉巖驾霜,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異买置,居然都是意外死亡粪糙,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門忿项,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蓉冈,“玉大人城舞,你說我怎么就攤上這事∧穑” “怎么了家夺?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長伐弹。 經(jīng)常有香客問我拉馋,道長,這世上最難降的妖魔是什么惨好? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任煌茴,我火速辦了婚禮,結(jié)果婚禮上昧狮,老公的妹妹穿的比我還像新娘景馁。我一直安慰自己板壮,他們只是感情好逗鸣,可當我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著绰精,像睡著了一般撒璧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上笨使,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天卿樱,我揣著相機與錄音,去河邊找鬼硫椰。 笑死繁调,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的靶草。 我是一名探鬼主播蹄胰,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼奕翔!你這毒婦竟也來了裕寨?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤派继,失蹤者是張志新(化名)和其女友劉穎宾袜,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體驾窟,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡庆猫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了绅络。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片阅悍。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡好渠,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出节视,到底是詐尸還是另有隱情拳锚,我是刑警寧澤,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布寻行,位于F島的核電站霍掺,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏拌蜘。R本人自食惡果不足惜杆烁,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望简卧。 院中可真熱鬧兔魂,春花似錦、人聲如沸举娩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽铜涉。三九已至智玻,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間芙代,已是汗流浹背吊奢。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留纹烹,地道東北人页滚。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像铺呵,于是被迫代替她去往敵國和親裹驰。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,490評論 2 348

推薦閱讀更多精彩內(nèi)容