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

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

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

前言:

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

system V共享內(nèi)存

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

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

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

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

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

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

1. shmget

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

原型:

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

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

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

2. shmat

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

原型:

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

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

  • shmid:由shmget返回的共享內(nèi)存段標(biāo)識(shí)符。
  • shmaddr:期望的映射地址,通常設(shè)置為NULL,讓操作系統(tǒng)自動(dòng)選擇地址。
  • shmflg:標(biāo)志位,常用的標(biāo)志是0(表示默認(rèn)映射),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)存段的標(biāo)識(shí)符。
  • cmd:控制命令,常用的命令有:
    • IPC_STAT:獲取共享內(nèi)存段的狀態(tài)。
    • IPC_RMID:刪除共享內(nèi)存段。
    • SHM_INFO:獲取共享內(nèi)存的統(tǒng)計(jì)信息。
  • buf:用于存儲(chǔ)共享內(nèi)存信息的結(jié)構(gòu)體,shmid_ds結(jié)構(gòu)體定義了共享內(nèi)存的狀態(tài)信息。

5.ftok

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

參數(shù):

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

返回值:

  • 成功時(shí)返回一個(gè) key_t 類型的唯一鍵值,可以用于標(biāo)識(shí) IPC 對(duì)象。
  • 失敗時(shí)返回 -1,并設(shè)置 errno 為相應(yīng)的錯(cuò)誤代碼。

shmid_ds結(jié)構(gòu)體

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

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

觀察shmif_ds結(jié)構(gòu)體

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

using namespace std;  // 使用標(biāo)準(zhǔn)命名空間,簡(jiǎn)化代碼書寫。

int main()
{
    // 獲取共享內(nèi)存段的標(biāo)識(shí)符
    int shmid = Getshmid();  
    // 使用shmat函數(shù)將共享內(nèi)存映射到進(jìn)程的地址空間
    char* shaddr = (char*)shmat(shmid, nullptr, 0);  
    // 定義一個(gè)shmid_ds結(jié)構(gòu)體,用于存儲(chǔ)共享內(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)存的權(quán)限
    cout << "權(quán)限: " << shmds.shm_perm.mode << endl;
    // 輸出共享內(nèi)存的大?。ㄗ止?jié)數(shù))
    cout << "共享內(nèi)存大小: " << shmds.shm_segsz << endl;
    // 輸出創(chuàng)建共享內(nèi)存的進(jìn)程ID
    cout << "創(chuàng)建共享內(nèi)存的進(jìn)程ID: " << shmds.shm_perm.mode << endl;
    // 輸出共享內(nèi)存的key值以及當(dāng)前程序自定義的key值
    cout << "共享內(nèi)存的key值: " << shmds.shm_perm.__key << "  自己創(chuàng)建的值:" << Get_key() << endl;
    
    // 使用shmdt解除共享內(nèi)存的映射
    shmdt((void*)shaddr);

    return 0;  // 結(jié)束程序
}

代碼的工作流程:

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

總結(jié)

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

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

1. 構(gòu)建管道類

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

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

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

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

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

2. 獲取key值

  • 獲取key:進(jìn)程通過(guò)ftok系統(tǒng)調(diào)用來(lái)計(jì)算出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 失敗,記錄錯(cuò)誤信息到日志,并返回 1
        log(fatal, "ftok failure:%s", strerror(errno)); // 錯(cuò)誤日志輸出,顯示 errno 對(duì)應(yīng)的錯(cuò)誤信息
        return 1; // 返回 1 表示錯(cuò)誤
    }
    // 如果成功,記錄成功信息到日志
    log(info, "GetKey success"); // 成功日志輸出
    // 返回生成的唯一 IPC 鍵值
    return key;

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

  • 創(chuàng)建共享內(nèi)存段:進(jìn)程使用 shmget 系統(tǒng)調(diào)用來(lái)創(chuàng)建或訪問(wèn)共享內(nèi)存段。
int GetShare_mm(int flag)
{
    // 使用獲取的 IPC 鍵值(通過(guò) GetKey 函數(shù))和共享內(nèi)存的大?。⊿IZE_MM)來(lái)調(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 失敗,記錄錯(cuò)誤信息到日志,并返回 2 作為錯(cuò)誤標(biāo)識(shí)
        log(fatal, "shmget failure: %s", strerror(errno)); // 錯(cuò)誤日志輸出,顯示 errno 對(duì)應(yīng)的錯(cuò)誤信息
        return 2; // 返回 2 表示共享內(nèi)存獲取失敗
    }
    // 如果 shmget 成功,記錄成功信息到日志
    log(info, "shmget success"); // 成功日志輸出
    // 返回獲取的共享內(nèi)存標(biāo)識(shí)符
    return shmid;
}

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

服務(wù)端:

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

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

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

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

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

客戶端:

#include "share.hpp"

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

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

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

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

相關(guān)文章

最新評(píng)論

霍林郭勒市| 井陉县| 江达县| 潍坊市| 措美县| 荥阳市| 嘉定区| 二手房| 贵定县| 双峰县| 阿巴嘎旗| 巨鹿县| 安阳市| 普兰店市| 张家口市| 沧源| 兴文县| 安泽县| 沙洋县| 加查县| 尚志市| 屏东县| 辉南县| 临湘市| 吉水县| 岚皋县| 广德县| 汝城县| 红原县| 永寿县| 泊头市| 鲁山县| 岳阳市| 巴中市| 麻栗坡县| 肇东市| 株洲县| 怀化市| 平舆县| 涟源市| 绩溪县|