欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Linux使用System?V實現(xiàn)內(nèi)存共享的最佳實踐

 更新時間:2025年07月23日 09:50:24   作者:chian-ocean  
System?V的共享內(nèi)存是Unix操作系統(tǒng)中一種進程間通信機制,它允許不同的進程通過共享一塊物理內(nèi)存區(qū)域來交換數(shù)據(jù),共享內(nèi)存提供了高效的進程間通信方式,因為進程可以直接讀寫共享區(qū)域,本文給大家介紹了在Linux上實現(xiàn)內(nèi)存共享的最佳實踐,需要的朋友可以參考下

前言:

System V的共享內(nèi)存是Unix操作系統(tǒng)中一種進程間通信(IPC)機制,它允許不同的進程通過共享一塊物理內(nèi)存區(qū)域來交換數(shù)據(jù)。共享內(nèi)存提供了高效的進程間通信方式,因為進程可以直接讀寫共享區(qū)域,而不需要通過內(nèi)核或其他進程的中介。

system V共享內(nèi)存

System V共享內(nèi)存的特點:

  1. 高效性:通過共享內(nèi)存,不同進程可以直接訪問和修改數(shù)據(jù),而不需要經(jīng)過數(shù)據(jù)復制的過程,減少了開銷。
  2. 持久性:共享內(nèi)存段在進程退出后仍然存在,直到顯式地由進程刪除。
  3. 權限控制:共享內(nèi)存段可以設定訪問權限,控制哪些進程可以讀寫共享內(nèi)存。

System V共享內(nèi)存流程:

  1. 獲取key:進程通過ftok系統(tǒng)調(diào)用來計算出key值.
  2. 創(chuàng)建共享內(nèi)存段:進程使用 shmget 系統(tǒng)調(diào)用來創(chuàng)建或訪問共享內(nèi)存段。
  3. 映射共享內(nèi)存:通過 shmat 系統(tǒng)調(diào)用,將共享內(nèi)存段映射到進程的虛擬地址空間中。
  4. 使用共享內(nèi)存:進程可以直接通過指針訪問共享內(nèi)存,就像訪問普通內(nèi)存一樣。
  5. 解除映射:進程使用 shmdt 來解除對共享內(nèi)存段的映射。
  6. 刪除共享內(nèi)存:當不再需要共享內(nèi)存時,進程通過 shmctl 來刪除共享內(nèi)存段。

system V共享內(nèi)存函數(shù):

在Unix系統(tǒng)中,System V共享內(nèi)存的操作由一系列系統(tǒng)調(diào)用來管理。以下是常用的共享內(nèi)存函數(shù):

1. shmget

功能:創(chuàng)建一個共享內(nèi)存段或獲取已經(jīng)存在的共享內(nèi)存段。

原型:

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

返回值:返回共享內(nèi)存段的標識符(一個非負整數(shù)),如果出錯,返回 -1。

  • key:共享內(nèi)存段的鍵值,用于標識共享內(nèi)存。如果是新創(chuàng)建的共享內(nèi)存段,key是唯一的。
  • size:共享內(nèi)存段的大?。ㄗ止?jié)數(shù))。
  • shmflg:標志位,控制共享內(nèi)存的訪問權限。常用標志有:
    • IPC_CREAT:如果共享內(nèi)存段不存在,則創(chuàng)建一個新段。
    • IPC_EXCL:與IPC_CREAT一起使用,如果共享內(nèi)存段已存在則調(diào)用失敗。
    • 0666:設置權限(可讀可寫)。

2. shmat

功能:將共享內(nèi)存段映射到進程的虛擬地址空間。

原型:

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

返回值:返回共享內(nèi)存的指針(映射到進程地址空間中)。如果失敗,則返回(void*) -1。

  • shmid:由shmget返回的共享內(nèi)存段標識符。
  • shmaddr:期望的映射地址,通常設置為NULL,讓操作系統(tǒng)自動選擇地址。
  • shmflg:標志位,常用的標志是0(表示默認映射),SHM_RDONLY(只讀映射)。

3. shmdt

功能:解除共享內(nèi)存的映射。

原型:

int shmdt(const void *shmaddr);

返回值:成功返回0,失敗返回-1

  • shmaddr:共享內(nèi)存的指針,通常是由shmat返回的指針。

4. shmctl

功能:控制共享內(nèi)存段的各種操作,例如獲取共享內(nèi)存段的狀態(tài)、刪除共享內(nèi)存段等。

原型

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

返回值:成功返回0,失敗返回-1

  • shmid:共享內(nèi)存段的標識符。
  • cmd:控制命令,常用的命令有:
    • IPC_STAT:獲取共享內(nèi)存段的狀態(tài)。
    • IPC_RMID:刪除共享內(nèi)存段。
    • SHM_INFO:獲取共享內(nèi)存的統(tǒng)計信息。
  • buf:用于存儲共享內(nèi)存信息的結構體,shmid_ds結構體定義了共享內(nèi)存的狀態(tài)信息。

5.ftok

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

參數(shù):

  • pathname:文件路徑名(文件或目錄的路徑),該文件必須存在且具有一定的權限。路徑名用于生成一個唯一的標識符。
  • proj_id:一個項目標識符,通常是一個字符值(例如 ‘A’、‘B’ 等)。這用于區(qū)分同一文件的不同用途。

返回值:

  • 成功時返回一個 key_t 類型的唯一鍵值,可以用于標識 IPC 對象。
  • 失敗時返回 -1,并設置 errno 為相應的錯誤代碼。

shmid_ds結構體

shmctl函數(shù)返回的shmid_ds結構體用于獲取共享內(nèi)存段的信息。它通常包含以下字段:

struct shmid_ds {
    struct ipc_perm shm_perm;  // 權限
    size_t shm_segsz;          // 共享內(nèi)存段大小
    time_t shm_atime;          // 最近一次附加時間
    time_t shm_dtime;          // 最近一次分離時間
    time_t shm_ctime;          // 創(chuàng)建時間
    pid_t shm_cpid;            // 創(chuàng)建該共享內(nèi)存段的進程ID
    pid_t shm_lpid;            // 最后操作該共享內(nèi)存段的進程ID
    shmatt_t shm_nattch;       // 附加到共享內(nèi)存的進程數(shù)
};

觀察shmif_ds結構體

#include"share.hpp"  // 引入頭文件,假設這是包含共享內(nèi)存相關函數(shù)聲明的頭文件。

using namespace std;  // 使用標準命名空間,簡化代碼書寫。

int main()
{
    // 獲取共享內(nèi)存段的標識符
    int shmid = Getshmid();  
    // 使用shmat函數(shù)將共享內(nèi)存映射到進程的地址空間
    char* shaddr = (char*)shmat(shmid, nullptr, 0);  
    // 定義一個shmid_ds結構體,用于存儲共享內(nèi)存段的狀態(tài)信息
    struct shmid_ds shmds;
    
    // 調(diào)用shmctl函數(shù)獲取共享內(nèi)存段的狀態(tài)
    int ret = shmctl(Getshmid(), IPC_STAT, &shmds);  
    // 輸出共享內(nèi)存的權限
    cout << "權限: " << shmds.shm_perm.mode << endl;
    // 輸出共享內(nèi)存的大小(字節(jié)數(shù))
    cout << "共享內(nèi)存大小: " << shmds.shm_segsz << endl;
    // 輸出創(chuàng)建共享內(nèi)存的進程ID
    cout << "創(chuàng)建共享內(nèi)存的進程ID: " << shmds.shm_perm.mode << endl;
    // 輸出共享內(nèi)存的key值以及當前程序自定義的key值
    cout << "共享內(nèi)存的key值: " << shmds.shm_perm.__key << "  自己創(chuàng)建的值:" << Get_key() << endl;
    
    // 使用shmdt解除共享內(nèi)存的映射
    shmdt((void*)shaddr);

    return 0;  // 結束程序
}

代碼的工作流程:

  1. 獲取共享內(nèi)存標識符 (shmid):通過Getshmid()獲取共享內(nèi)存的標識符。Getshmid()應該是用戶自己定義的一個函數(shù),返回有效的共享內(nèi)存段ID。
  2. 映射共享內(nèi)存:通過shmat函數(shù)將共享內(nèi)存段映射到當前進程的地址空間。這里使用的是nullptr,表示操作系統(tǒng)會自動選擇一個合適的地址來映射共享內(nèi)存。
  3. 獲取共享內(nèi)存信息:調(diào)用shmctl函數(shù)并使用IPC_STAT命令來獲取共享內(nèi)存段的狀態(tài),保存在shmid_ds結構體中。這個結構體包含了共享內(nèi)存的權限、大小、創(chuàng)建進程ID、key值等信息。
  4. 輸出共享內(nèi)存的信息:輸出共享內(nèi)存的權限、大小、創(chuàng)建進程ID以及key值。注意,在輸出創(chuàng)建共享內(nèi)存的進程ID時,代碼中有個小錯誤,應改為shmds.shm_cpid,而不是shmds.shm_perm.mode,因為mode字段是權限信息。
  5. 解除共享內(nèi)存映射:調(diào)用shmdt函數(shù)解除映射,防止進程泄露資源。

總結

  • shmget用于創(chuàng)建和訪問共享內(nèi)存段。
  • shmat用于將共享內(nèi)存段映射到進程的地址空間。
  • shmdt用于解除共享內(nèi)存的映射。
  • shmctl用于控制共享內(nèi)存段,例如刪除或查看信息。

共享內(nèi)存通信實例(管道控制同步)

1. 構建管道類

class FIFO
{
public:
    // 構造函數(shù):創(chuàng)建命名管道(FIFO)
    FIFO()
    {
        // 調(diào)用 mkfifo 創(chuàng)建命名管道,MYFIFO_PATH 是管道的路徑,MODE 是文件權限
        int n = mkfifo(MYFIFO_PATH, MODE);
        
        // 檢查 mkfifo 是否成功,若返回值為 -1,則表示創(chuàng)建失敗
        if (n == -1)
        {
            // 如果創(chuàng)建失敗,記錄錯誤日志并退出程序
            log(fatal, "mkfifo failure: %s", strerror(errno));  // 輸出錯誤日志,顯示錯誤原因
            exit(4);  // 返回 4 表示創(chuàng)建管道失敗
        }
        
        // 如果創(chuàng)建成功,記錄成功日志
        log(info, "mkfifo success");  // 輸出成功日志
    }

    // 析構函數(shù):刪除命名管道
    ~FIFO()
    {
        // 調(diào)用 unlink 刪除命名管道
        int n = unlink(MYFIFO_PATH);
        
        // 檢查 unlink 是否成功,若返回值為 -1,則表示刪除失敗
        if (n == -1)
        {
            // 如果刪除失敗,記錄錯誤日志并退出程序
            log(error, "unlink failure: %s", strerror(errno));  // 輸出錯誤日志,顯示錯誤原因
            exit(4);  // 返回 4 表示刪除管道失敗
        }
        
        // 如果刪除成功,記錄成功日志
        log(info, "unlink success");  // 輸出成功日志
    }
};

FIFO 類用于創(chuàng)建和刪除命名管道(FIFO)。

構造函數(shù):在對象創(chuàng)建時,調(diào)用 mkfifo 創(chuàng)建命名管道。如果創(chuàng)建失敗,記錄錯誤并退出程序。

析構函數(shù):在對象銷毀時,調(diào)用 unlink 刪除命名管道。如果刪除失敗,記錄錯誤并退出程序。

2. 獲取key值

  • 獲取key:進程通過ftok系統(tǒng)調(diào)用來計算出key值.
key_t GetKey()
{
    // 調(diào)用 ftok 函數(shù),使用 pathname 和 proj_id 生成唯一的 IPC 鍵值
    key_t key = ftok(pathname.c_str(), proj_id);    
    // 檢查 ftok 調(diào)用是否成功,key < 0 表示失敗
    if (key < 0)
    {
        // 如果 ftok 失敗,記錄錯誤信息到日志,并返回 1
        log(fatal, "ftok failure:%s", strerror(errno)); // 錯誤日志輸出,顯示 errno 對應的錯誤信息
        return 1; // 返回 1 表示錯誤
    }
    // 如果成功,記錄成功信息到日志
    log(info, "GetKey success"); // 成功日志輸出
    // 返回生成的唯一 IPC 鍵值
    return key;

3.創(chuàng)建共享內(nèi)存段

  • 創(chuàng)建共享內(nèi)存段:進程使用 shmget 系統(tǒng)調(diào)用來創(chuàng)建或訪問共享內(nèi)存段。
int GetShare_mm(int flag)
{
    // 使用獲取的 IPC 鍵值(通過 GetKey 函數(shù))和共享內(nèi)存的大?。⊿IZE_MM)來調(diào)用 shmget 創(chuàng)建或獲取共享內(nèi)存
    int shmid = shmget(GetKey(), SIZE_MM, flag);
    
    // 檢查 shmget 調(diào)用是否成功,如果返回值是 -1 表示創(chuàng)建或獲取共享內(nèi)存失敗
    if (shmid == -1)
    {
        // 如果 shmget 失敗,記錄錯誤信息到日志,并返回 2 作為錯誤標識
        log(fatal, "shmget failure: %s", strerror(errno)); // 錯誤日志輸出,顯示 errno 對應的錯誤信息
        return 2; // 返回 2 表示共享內(nèi)存獲取失敗
    }
    // 如果 shmget 成功,記錄成功信息到日志
    log(info, "shmget success"); // 成功日志輸出
    // 返回獲取的共享內(nèi)存標識符
    return shmid;
}

4.映射、使用和銷毀共享內(nèi)存

服務端:

int main()
{
    // 創(chuàng)建一個命名管道 FIFO
    FIFO init;  // 假設 FIFO 是一個類,它的構造函數(shù)用于初始化命名管道。

    // 打開命名管道,打開模式是只讀
    int fd = open("myfifo", O_RDONLY);
    if (fd == -1)
    {
        // 如果打開管道失敗,記錄錯誤并退出
        log(error, "open failure: %s", strerror(errno)); // 錯誤日志輸出,顯示 errno 對應的錯誤信息
        exit(5); // 返回 5 表示出現(xiàn)錯誤并退出
    }

    // 創(chuàng)建共享內(nèi)存并獲取共享內(nèi)存標識符
    int shmid = CreateShmid();  // 假設 CreateShmid() 是創(chuàng)建共享內(nèi)存的函數(shù),它返回共享內(nèi)存段的標識符。

    // 將共享內(nèi)存映射到進程的地址空間
    char* shmaddr = (char*)shmat(shmid, nullptr, 0);
    if ((void*)shmaddr == (void*)-1)
    {
        // 如果共享內(nèi)存映射失敗,記錄錯誤并返回
        log(fatal, "shmat failure: %s", strerror(errno)); // 錯誤日志輸出
        return 1; // 返回 1 表示出錯
    }

    // 進入通信循環(huán)
    while (true)
    {
        char ch; 
  • 創(chuàng)建管道:使用 FIFO 類創(chuàng)建命名管道。
  • 打開管道:調(diào)用 open("myfifo", O_RDONLY) 打開管道進行讀取。如果失敗,記錄錯誤并退出。
  • 創(chuàng)建共享內(nèi)存:使用 CreateShmid() 創(chuàng)建共享內(nèi)存。、
  • 映射共享內(nèi)存:使用 shmat() 將共享內(nèi)存映射到進程地址空間,檢查映射是否成功。
  • 通信循環(huán):從管道讀取字符,輸出共享內(nèi)存內(nèi)容,直到讀取結束。
  • 解除映射與清理:使用 shmdt() 解除共享內(nèi)存映射,調(diào)用 DeleteShare() 刪除共享內(nèi)存,釋放資源。

客戶端:

#include "share.hpp"

int main()
{
    // 打開命名管道 "myfifo" 進行寫操作 (O_WRONLY)
    int fd = open("myfifo", O_WRONLY);
    if (fd == -1)  // 如果打開管道失敗,fd 會是 -1
    {
        // 記錄管道打開失敗的錯誤信息并退出程序
        log(error, "open failure: %s", strerror(errno)); 
        exit(5);  // 退出程序,返回錯誤碼 5
    }
    // 獲取共享內(nèi)存的標識符
    int shmid = Getshmid();

    // 將共享內(nèi)存映射到進程地址空間
    char* shmaddr = (char*)shmat(shmid, nullptr, 0);
    if ((void*)shmaddr == (void*)-1)  // 檢查映射是否成功
    {
        // 如果映射失敗,記錄錯誤信息并退出程序
        log(fatal, "shmat failure: %s", strerror(errno));
        return 1;  // 返回錯誤碼 1
    }
    // 進入通信循環(huán)
    while (true)
    {
        // 提示用戶輸入
        std::cout << "Please Enter@ ";
        // 從標準輸入讀取數(shù)據(jù)并存儲到共享內(nèi)存
        fgets(shmaddr, SIZE_MM, stdin);  

        // 向管道寫入字符 'x',表示有新的消息
        int n = write(fd, "x", sizeof(char));  
    }
    // 解除共享內(nèi)存映射
    shmdt((void*)shmaddr);
    return 0;  // 正常退出
}
  • 打開管道:通過 open("myfifo", O_WRONLY) 打開管道進行寫操作。如果失敗,記錄錯誤并退出。
  • 獲取共享內(nèi)存:使用 Getshmid() 獲取共享內(nèi)存標識符,使用 shmat() 將共享內(nèi)存映射到進程地址空間。
  • 通信循環(huán):不斷提示用戶輸入,將用戶輸入存儲到共享內(nèi)存中,并向管道寫入字符 'x' 表示有新的數(shù)據(jù)。、
  • 解除映射并退出:調(diào)用 shmdt() 解除共享內(nèi)存映射,程序正常退出。

以上就是Linux使用System V實現(xiàn)內(nèi)存共享的最佳實踐的詳細內(nèi)容,更多關于Linux System V內(nèi)存共享的資料請關注腳本之家其它相關文章!

相關文章

  • Linux簡介及最常用命令(簡單易學,但能解決95%以上的問題)

    Linux簡介及最常用命令(簡單易學,但能解決95%以上的問題)

    這篇文章主要介紹了Linux簡介及最常用命令(簡單易學,但能解決95%以上的問題),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-08-08
  • 阿里云linux服務器下安裝Apache的簡單方法

    阿里云linux服務器下安裝Apache的簡單方法

    本文介紹下,在阿里云的linux服務器上,安裝apache的簡單方法,需要的朋友可以參考下
    2014-05-05
  • Linux下rsync遠程數(shù)據(jù)同步命令的詳細介紹

    Linux下rsync遠程數(shù)據(jù)同步命令的詳細介紹

    rsync是一款開源的、快速的、多功能的、可實現(xiàn)全量及增量的本地或遠程數(shù)據(jù)同步備份的優(yōu)秀工具。rsync軟件適用于unix/linux/windows等多種操作系統(tǒng)平臺。下面這篇文章主要介紹了Linux下rsync命令的相關資料,需要的朋友可以參考借鑒。
    2017-02-02
  • Apache Web 服務器的安裝配置方法

    Apache Web 服務器的安裝配置方法

    學習如何在 Apache 上托管你自己的網(wǎng)站,這是一個可靠、流行且易于配置的 Web 服務器。Apache Web 服務器的安裝和配置必須以 root 身份執(zhí)行,接下來通過本文給大家介紹Apache Web 服務器的安裝配置方法,需要的朋友參考下吧
    2018-10-10
  • Linux安裝Python虛擬環(huán)境virtualenv的方法

    Linux安裝Python虛擬環(huán)境virtualenv的方法

    下面小編就為大家?guī)硪黄狶inux安裝Python虛擬環(huán)境virtualenv的方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-01-01
  • Linux密碼安全防護操作詳解

    Linux密碼安全防護操作詳解

    這篇文章主要為大家詳細介紹了一些Linux密碼的安全防護操作,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • centos7 無線網(wǎng)卡驅動的安裝及無線網(wǎng)絡的配置詳解

    centos7 無線網(wǎng)卡驅動的安裝及無線網(wǎng)絡的配置詳解

    本篇文章主要介紹了centos7 無線網(wǎng)卡驅動的安裝及無線網(wǎng)絡的配置詳解,具有一定的參考價值,有興趣的可以了解一下。
    2017-03-03
  • apache配置訪問站點下所有文件的實現(xiàn)

    apache配置訪問站點下所有文件的實現(xiàn)

    本文主要介紹了配置Apache服務器以實現(xiàn)對根目錄下目錄的訪問控制,包括無限制訪問和有限制訪問,具有一定的參考價值,感興趣的可以了解一下
    2025-03-03
  • Linux中一種友好的find替代工具(fd命令)

    Linux中一種友好的find替代工具(fd命令)

    這篇文章主要介紹了Linux中一種友好的find替代工具(fd命令),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-11-11
  • 限制 Apache日志文件大小的方法

    限制 Apache日志文件大小的方法

    access.log,件在 WEB 服務器運行一段時間之后會達到幾十兆甚至上百兆,如果Apache運行有錯誤,error.log也會增大到幾十兆,我們知道系統(tǒng)讀寫一個大的文本文件是非常耗內(nèi)存的,因此限定日志文件大小十分必要。
    2009-04-04

最新評論