【Linux从入门到精通】通信 | 共享内存(System V)

这篇具有很好参考价值的文章主要介绍了【Linux从入门到精通】通信 | 共享内存(System V)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【Linux从入门到精通】通信 | 共享内存(System V),Linux从入门到精通,linux,运维,通信,共享内存 

  本篇文章接着上篇文章通信 | 管道通信(匿名管道 & 命名管道)进行讲解。本篇文章的中点内容是共享内存

文章目录

 一、初识与创建共享内存

1、1 什么是共享内存

1、2 共享内存函数

1、2、1 创建共享内存 shmget

1、2、2 ftok 生成 key

1、2、3 获取共享内存 shmget

1、3 demo 代码

二、对共享内存进行相关操作 

2、1 查看/删除 共享内存资源

2、2 共享内存挂接和访问

2、2、1 共享内存的挂接 shmat()

2、2、2 共享内存的访问

2、3 删除共享内存 shmctl 

三、完整共享内存通信 demo 代码

3、1 Log.hpp 日志

3、2 comm.hpp

3、3 shmClient.cpp

3、4 shmServer.cpp


🙋‍♂️ 作者:@Ggggggtm 🙋‍♂️

👀 专栏:Linux从入门到精通  👀

💥 标题:共享内存 💥

 ❣️ 寄语:与其忙着诉苦,不如低头赶路,奋路前行,终将遇到一番好风景 ❣️

 一、初识与创建共享内存

1、1 什么是共享内存

  我们在之前学管道通信时,是怎么实现通信的呢?匿名管道通信的方式是子进程继承父进程的内核数据结构,使得父子进程能够看到同一块空间命名管道信是让不同进程打开同一份文件。我们发现通信的前提就是让不同的进程看到同一份“资源”。当然,共享内存也不例外。

   每个进程都有自己独立的地址空间,所以它们彼此之间不能直接访问对方的内存。而共享内存则提供了一种特殊的内存区域,允许多个进程可以同时访问和操作同一块内存。具体如下图:

【Linux从入门到精通】通信 | 共享内存(System V),Linux从入门到精通,linux,运维,通信,共享内存

  这里再次解释一下上图。我们创建共享内存的过程:一个进程在内核空间申请一个共享内存对象,让后通过页表建立与物理内存的映射。让后另一个进程通过特殊的方法和算法来找到该共享内存并且与其建立映射。下面我们会对上述过程进行详细解释。 

1、2 共享内存函数

1、2、1 创建共享内存 shmget

  shmget函数用于创建一个新的共享内存段或者获取现有的共享内存段的标识符

函数原型为:

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

参数说明:

  • key:用于标识共享内存段的键值。可以使用ftok函数生成
  • size:指定共享内存段的大小,以字节为单位。
  • shmflg:用于指定共享内存段的访问权限和标志位,可以使用IPC_CREAT、IPC_EXCL等宏进行设置。

返回值:

  • 如果成功,返回共享内存段的标识符(即共享内存ID)。
  • 如果失败,返回-1,并设置errno。

  更加详细的如下图:

【Linux从入门到精通】通信 | 共享内存(System V),Linux从入门到精通,linux,运维,通信,共享内存

  我们在这里具体解释一下第三个参数 shmflg。这个参数是可以有多个选择的。底层是利用了位图的思想。主要是IPC_CREAT和IPC_EXCL两个选项。

  IPC_CREAT和IPC_EXCL是在shmget函数中使用的标志位,用于指定共享内存段的访问权限和标志。它们在shmget函数的第三个参数shmflg中使用。

  • IPC_CREAT:该标志用于创建一个新的共享内存段。如果指定的key对应的共享内存段不存在,则创建一个新的共享内存段。如果共享内存段已经存在,则返回该共享内存段的标识符(即共享内存ID)。

  • IPC_EXCL:该标志与IPC_CREAT一起使用,在创建共享内存段时起作用。如果指定的key对应的共享内存段已经存在,则shmget函数会失败,并返回-1,并且置errno为EEXIST(资源已存在)。

   我们接下来再看一下 shmget 的具体使用例子。

int shmid = shmget(key, size, IPC_CREAT | permission_flags);

  上述代码中,IPC_CREAT标志位用于创建共享内存段。如果指定的key对应的共享内存段已经存在,那么shmget函数会返回该共享内存段的标识符;如果共享内存段不存在,则会创建一个新的共享内存段,并返回新创建的共享内存段的标识符。

1、2、2 ftok 生成 key

  在函数shmget中,key值是用于标识或检索共享内存段的关键值。它在创建或访问共享内存时起到重要作用。具体来说,key值用于以下两个目的:

  • 当多个进程需要访问同一个共享内存段时,它们可以使用相同的key值来标识这个共享内存段。
  • 如果一个共享内存段已经存在,并且其他进程想要访问它,那么只需要提供相同的key值即可找到该共享内存段。

  那在使用 shmget 函数之前,我们应该使用 ftok 函数生成key值,来表示这个共享内存段。由于是标示共享空间,所以应该确定唯一性。至于key的值是多少并不关键。那我们看一下ftok 函数的用法。具体如下:

【Linux从入门到精通】通信 | 共享内存(System V),Linux从入门到精通,linux,运维,通信,共享内存

参数说明:

  • pathname:一个包含一个现有文件的路径名,用于生成k值。最好是有权访问这个文件。
  • proj_id:不同的proj_id可以被用作区分不同类型的通信方式或不同的ipc资源,来生成不同的k值。其实就是一个任意整型值。

  我们再看一下其具体的例子:

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>

int main()
{
    key_t key;
    char *path = "./example.txt";
    int proj_id = 0x66;

    // 使用ftok函数生成k值
    key = ftok(path, proj_id);

    printf("Generated key: %d\n", key);

    return 0;
}

  另一个进程也可以用相同的方法生成相同的key值。ftok函数根据给定的路径名和proj_id生成k值。当路径名和proj_id相同时,生成的k值也相同。这是因为ftok函数内部使用了哈希运算,将路径名和proj_id转化为一个唯一的整数。尽管可能存在哈希冲突(即不同的路径名和proj_id生成相同的k值),但概率非常低。通常情况下,不同的进程可以使用相同的路径名和proj_id生成相同的k值是非常罕见的。即使出现相同的k值,由于进程间通信中还有其他参数的限制(如消息队列标识、共享内存标识等),不同进程之间的IPC通信仍然可以正常进行。  

  生成 key 值后,我们就可以用key值创建共享内存,或者来获取共享内存。下面我们看一下获取使用key值来获取共享内存的方法。

1、2、3 获取共享内存 shmget

  shmget 函数还可用来获取共享内存。当生成的key值已经有对应的共享内存时,shmget 函数就会返回这段共享内存的标识码。我么不只需要将第三个参数修改为0,就是来获取对应key值的共享内存。

1、3 demo 代码

  我们接下来写一段代码测试和总结一下我们上面所学到的函数。下面为实例:

// Log.hpp
#include <iostream>
#include <ctime>

#define Debug   0
#define Notice  1
#define Warning 2
#define Error   3


const std::string msg[] = {
    "Debug",
    "Notice",
    "Warning",
    "Error"
};

std::ostream &Log(std::string message, int level)
{
    std::cout << " | " << (unsigned)time(nullptr) << " | " << msg[level] << " | " << message;
    return std::cout;
}


// comm.hpp
#pragma once

#include <iostream>
#include <cstdio>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <cassert>
#include <cstring>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "Log.hpp"

using namespace std; 

#define PATH_NAME "/home/gtm"
#define PROJ_ID 0x66
#define SHM_SIZE 4096 //共享内存的大小,最好是页(PAGE: 4096)的整数倍

#define FIFO_NAME "./fifo"


// shmClient.cc
#include"comm.hpp"

int main()
{
    Log("child pid is : ", Debug) << getpid() << endl;
    key_t k = ftok(PATH_NAME, PROJ_ID);
    if (k < 0)
    {
        Log("create key failed", Error) << " client key : " << k << endl;
        exit(1);
    }
    Log("create key done", Debug) << " client key : " << k << endl;

    // 获取共享内存
    int shmid = shmget(k, SHM_SIZE, 0);
    if(shmid < 0)
    {
        Log("create shm failed", Error) << " client key : " << k << endl;
        exit(2);
    }
    Log("create shm success", Error) << " client shmid : " << shmid << endl;


    return 0;
}


// shmServer.cc
#include "comm.hpp"

string TransToHex(key_t k)
{
    char buffer[32];
    snprintf(buffer, sizeof buffer, "0x%x", k);
    return buffer;
}

int main()
{
    // 我们之前为了通信,所做的所有的工作,属于什么工作呢:让不同的进程看到了同一份资源(内存)
    // 1. 创建公共的Key值
    key_t k = ftok(PATH_NAME, PROJ_ID);
    assert(k != -1);

    Log("create key done", Debug) << " server key : " << TransToHex(k) << endl;

    // 2. 创建共享内存 -- 建议要创建一个全新的共享内存 -- 通信的发起者
    int shmid = shmget(k, SHM_SIZE, IPC_CREAT | IPC_EXCL | 0666); //
    if (shmid == -1)
    {
        perror("shmget");
        exit(1);
    }
    Log("create shm done", Debug) << " shmid : " << shmid << endl;
    
    return 0;
}

  shmServer.cc文件中的代码是服务端代码。首先调用ftok函数生成一个唯一的键值,并将其转换为十六进制字符串表示。然后使用shmget函数创建一个共享内存段,创建时指定了IPC_CREAT标志,用于新建共享内存段。如果创建成功,返回一个共享内存标识符shmid。

  shmClient.cc文件中的代码是客户端代码。首先也是调用ftok函数生成一个唯一的键值。然后通过shmget函数打开已存在的共享内存段,打开时不需要指定IPC_CREAT标志,而是提供即将打开的共享内存段的键值和大小。如果打开成功,返回一个共享内存标识符shmid。

  Log.hpp文件定义了一个宏和一个Log函数。宏定义了四个日志级别,分别对应Debug、Notice、Warning和Error四个字符串。Log函数负责输出日志信息,接受一个字符串信息和一个日志级别参数。Log函数将时间戳、日志级别和消息内容输出到标准输出流中。

  上述代码就是完成了创建共享内存的功能,并且在其中打印了一些日志信息。我们不妨来看一下运行结果。具体如下图:

【Linux从入门到精通】通信 | 共享内存(System V),Linux从入门到精通,linux,运维,通信,共享内存

  我们发现对应的shmid是相同的,说明Server和Client确实获得了相同的共享内存块。他们所生成的key值相同吗?其实是相同的,如下图:

【Linux从入门到精通】通信 | 共享内存(System V),Linux从入门到精通,linux,运维,通信,共享内存

二、对共享内存进行相关操作 

2、1 查看/删除 共享内存资源

  当我们再次运行时,就会发生错误。具体如下图:

【Linux从入门到精通】通信 | 共享内存(System V),Linux从入门到精通,linux,运维,通信,共享内存

  为什么呢?原因是我们刚刚创建的共享内存依然存在。当进程结束时,共享内存并不会自动释放。为什么呢?我们可以认为共享内存是属于操作系统。所以共享内存的生命周期随操作系统!这时我们可以手动关闭共享内存。在关闭前首先要查看共享内存,指令:ipcs -m。具体如下图:

【Linux从入门到精通】通信 | 共享内存(System V),Linux从入门到精通,linux,运维,通信,共享内存

  当然,查到共享内存后,可以用指令进行删除。那么问题来了,使用key值删除呢?还是用shmid 进行删除呢?我们这里需要注意:共享内存中的shmid和key值是两个不同的概念

  1. shmid(Shared Memory ID)是共享内存的标识符,由操作系统分配,并作为一个非负整数对共享内存进行引用。在使用共享内存时,我们需要通过shmid来进行操作,如创建、附加、访问和删除等。shmid可以看作是内核用于标识某个特定共享内存段的一个唯一值

  2. key值是用户定义的一个标识符,通常是一个整数值。在创建共享内存时,我们可以使用ftok函数生成一个key值,以便其他进程可以通过这个key值来获取相同的共享内存区域。key值是用于标识共享内存的用户级别的标识符,不同于shmid,其值不受内核控制

  所以删除共享内存,我们使用的shmid。具体指令:ipcrm -m shmid。如下图:

【Linux从入门到精通】通信 | 共享内存(System V),Linux从入门到精通,linux,运维,通信,共享内存

  当我们删除共享内存后,再次进行查找发现就没有了,且程序能够正常运行。

2、2 共享内存挂接和访问

2、2、1 共享内存的挂接 shmat()

  在调用shmget()函数时,内核会在内部维护一个共享内存表格,其中包含了共享内存的相关信息,包括共享内存的大小、权限等。当调用成功后,将返回一个唯一的共享内存标识符,该标识符可以用于后续的共享内存操作。

  那么正常来说,我们访问共享内存是需要通过系统调用的。但是我们这里可以将内核级别的共享内存挂接到进程的地址空间。然后用户就可以直接进行访问

  进程可以使用系统提供的函数(如shmat())将自己的地址空间映射到共享内存。也可以理解为shmat()函数将共享内存附加到进程的虚拟地址空间中,使得进程可以访问该共享内存所指向的物理内存区域。具体用法如下:

【Linux从入门到精通】通信 | 共享内存(System V),Linux从入门到精通,linux,运维,通信,共享内存

  参数说明:

  • shm_id:共享内存标识符,通过调用 shmget 获取。
  • shm_addr:内存段的地址,通常传入 NULL,表示由系统自动选择一个适合的地址。
  • shmflg:控制共享内存段的附加方式和权限,可以使用 IPC_CREAT 标志创建新的共享内存段。通常传入0。

  返回值:

  • 如果成功,返回指向共享内存段第一个字节的指针;
  • 如果失败,返回 void * 类型的错误值 -1

  其实我们看完其使用方法后,有没有发现与 malloc 很相似。malloc 申请空间成功后,会返回所申请空间的起始地址。否则就会返回NULL。shmat 与其确实有些相似。我们可结合如下例子一起理解:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>

int main() {
    int shm_id;
    key_t key;
    int *shared_memory;

    // 获取共享内存标识符
    key = ftok("。/file", 0x66);
    shm_id = shmget(key, sizeof(int), IPC_CREAT | 0666);
    
    // 将共享内存段附加到进程的地址空间中
    shared_memory = shmat(shm_id, NULL, 0);
    
    // 访问共享内存
    printf("共享内存中的值为:%d\n", *shared_memory);
    
    // 分离共享内存段
    shmdt(shared_memory);
    
    return 0;
}

  我们也看到了最后是有一个去关联的 shmdt 函数。参数就是我们所获取的共享内存的起始地址,这里就不再过多解释此函数

  这里有会有一个问题:将内核级别的共享内存挂接到进程地址空间的哪里了呢?我们看如下图:

【Linux从入门到精通】通信 | 共享内存(System V),Linux从入门到精通,linux,运维,通信,共享内存   我们之前学进程地址空间时,知道堆和栈的中间有大量的镂空,而这段位置就是内核级别的共享内存所挂接到的位置!

2、2、2 共享内存的访问

  到这里,我们已经学习了共享内存的大部分内容。只差对共享内存的访问了。当我们对共享内存进行挂接后, 就可以得到共享内存挂接后的起始地址。我们用户可以对其进行直接访问(写入/读取)。我们给出如下伪代码:

    // shmServer.cpp
    char *shmaddr = (char *)shmat(shmid, nullptr, 0);
    Log("attach shm done", Debug) << " shmid : " << shmid << endl;

    for(;;)
    {
        printf("%s\n", shmaddr);
        if(strcmp(shmaddr, "quit") == 0) break;
        sleep(1);
    }

    // shmClient.cpp  
    // 挂接并获得共享内存起始地址
    char *shmaddr = (char *)shmat(shmid, nullptr, 0);
    if(shmaddr == nullptr)
    {
        Log("attach shm failed", Error) << " client key : " << k << endl;
        exit(3);
    }

    char a = 'a';
    for(; a <= 'c'; a++)
    {
        // 我们是每一次都向shmaddr[共享内存的起始地址]写入
        snprintf(shmaddr, SHM_SIZE - 1,\
            "hello server, 我是其他进程,我的pid: %d, inc: %c\n",\
            getpid(), a);
        sleep(3);
    }

  对上述代码是一个使用共享内存进行进程间通信的伪代码。下面对代码进行详解:

  1. 首先,在服务端(shmServer.cpp)中,通过shmat函数将共享内存连接到当前进程的地址空间。shmat函数的第一个参数是共享内存的标识符shmid,第二个参数为NULL表示让系统自动选择合适的地址分配给共享内存,第三个参数为0表示以默认权限进行操作。连接完成后,返回共享内存的起始地址,并赋值给shmaddr指针。

  2. 服务器端的for循环中,通过printf函数将shmaddr指向的共享内存内容输出到标准输出(读取)。然后通过strcmp函数判断共享内存中的内容是否为"quit",如果是,则跳出循环,结束程序。否则,通过sleep函数暂停1秒钟。

  3. 在客户端(shmClient.cpp)中,同样通过shmat函数连接到共享内存,并将共享内存的起始地址赋给shmaddr指针。若连接失败(shmaddr为nullptr),则输出错误信息并退出程序。

  4. 客户端的for循环中,使用snprintf函数将格式化的字符串写入shmaddr指向的共享内存中(写入)。该字符串包含了客户端进程的PID(进程标识符)和一个递增的字符,以展示多次写入的内容。然后通过sleep函数暂停3秒钟。

  运行结果如下:

【Linux从入门到精通】通信 | 共享内存(System V),Linux从入门到精通,linux,运维,通信,共享内存

  我们通过运行结果发现:在客户端没有写入的情况下,服务端进行读取时也会读到内容。读到的是空字符串(共享内存默认会初始化为0)。我们发现共享内存的读写并没有访问控制。我们知道命名管道通信是由访问控制的。但是当一个进程写入时,另一个就能够马上看到写入的内容。所以共享内存是所有进程间通信(IPC),速度最快的!不需要过多的拷贝!!(不需要将数据给操作系统)。如果我想一定程度的访问控制呢?可以在共享内存读写的过程中加入命名管道来控制。

2、3 删除共享内存 shmctl 

  上面我们了解了可以使用Linux指令对共享内存进行删除,我们也可以使用系统调用 shmctl()函数 对其进行删除。具体使用如下:

【Linux从入门到精通】通信 | 共享内存(System V),Linux从入门到精通,linux,运维,通信,共享内存 参数说明:

  • shmid:共享内存标识符,通过shmget函数获取得到。
  • cmd:表示对共享内存进行的操作类型,可以选择的参数有:
    • IPC_STAT:获取共享内存的状态信息,将共享内存的属性保存在buf所指向的结构体中。
    • IPC_SET:设置共享内存的属性,使用buf所指向的结构体中的值进行设置。
    • IPC_RMID:删除共享内存。
  • buf:指向一个struct shmid_ds结构体的指针,用于存储共享内存的属性信息。通常使用nullptr。

  shmctl函数可以用于对共享内存段进行控制操作。它能够实现共享内存的创建、删除、以及获取和修改共享内存的属性。但是我们该函数最常用删除共享内存。使用IPC_RMID操作可以删除指定的共享内存段,并释放系统资源。这个操作会立即删除共享内存段,以及与它关联的任何进程中的键和id

三、完整共享内存通信 demo 代码

3、1 Log.hpp 日志

  

#include <iostream>
#include <ctime>

#define Debug   0
#define Notice  1
#define Warning 2
#define Error   3


const std::string msg[] = {
    "Debug",
    "Notice",
    "Warning",
    "Error"
};

std::ostream &Log(std::string message, int level)
{
    std::cout << " | " << (unsigned)time(nullptr) << " | " << msg[level] << " | " << message;
    return std::cout;
}

3、2 comm.hpp

#pragma once

#include <iostream>
#include <cstdio>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <cassert>
#include <cstring>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "Log.hpp"

using namespace std; //不推荐

#define PATH_NAME "/home/whb"
#define PROJ_ID 0x66
#define SHM_SIZE 4096 //共享内存的大小,最好是页(PAGE: 4096)的整数倍

#define FIFO_NAME "./fifo"

class Init
{
public:
    Init()
    {
        umask(0);
        int n = mkfifo(FIFO_NAME, 0666);
        assert(n == 0);
        (void)n;
        Log("create fifo success",Notice) << "\n";
    }
    ~Init()
    {
        unlink(FIFO_NAME);
        Log("remove fifo success",Notice) << "\n";
    }
};

#define READ O_RDONLY
#define WRITE O_WRONLY

int OpenFIFO(std::string pathname, int flags)
{
    int fd = open(pathname.c_str(), flags);
    assert(fd >= 0);
    return fd;
}

void Wait(int fd)
{
    Log("等待中....", Notice) << "\n";
    uint32_t temp = 0;
    ssize_t s = read(fd, &temp, sizeof(uint32_t));
    assert(s == sizeof(uint32_t));
    (void)s;
}

void Signal(int fd)
{
    uint32_t temp = 1;
    ssize_t s = write(fd, &temp, sizeof(uint32_t));
    assert(s == sizeof(uint32_t));
    (void)s;
    Log("唤醒中....", Notice) << "\n";
}

void CloseFifo(int fd)
{
    close(fd);
}

3、3 shmClient.cpp

#include "comm.hpp"

int main()
{
    Log("child pid is : ", Debug) << getpid() << endl;
    key_t k = ftok(PATH_NAME, PROJ_ID);
    if (k < 0)
    {
        Log("create key failed", Error) << " client key : " << k << endl;
        exit(1);
    }
    Log("create key done", Debug) << " client key : " << k << endl;

    // 获取共享内存
    int shmid = shmget(k, SHM_SIZE, 0);
    if(shmid < 0)
    {
        Log("create shm failed", Error) << " client key : " << k << endl;
        exit(2);
    }
    Log("create shm success", Error) << " client key : " << k << endl;

    // sleep(10);

    char *shmaddr = (char *)shmat(shmid, nullptr, 0);
    if(shmaddr == nullptr)
    {
        Log("attach shm failed", Error) << " client key : " << k << endl;
        exit(3);
    }
    Log("attach shm success", Error) << " client key : " << k << endl;


    int fd = OpenFIFO(FIFO_NAME, WRITE);

    // client将共享内存看做一个char 类型的buffer
    while(true)
    {
        ssize_t s = read(0, shmaddr, SHM_SIZE-1);
        if(s > 0)
        {
            shmaddr[s-1] = 0;
            Signal(fd);
            if(strcmp(shmaddr,"quit") == 0) break;
        }
    }

    CloseFifo(fd);

    // 去关联
    int n = shmdt(shmaddr);
    assert(n != -1);
    Log("detach shm success", Error) << " client key : " << k << endl;


    return 0;
}

3、4 shmServer.cpp

#include "comm.hpp"

Init init; 

string TransToHex(key_t k)
{
    char buffer[32];
    snprintf(buffer, sizeof buffer, "0x%x", k);
    return buffer;
}

int main()
{
    // 1. 创建公共的Key值
    key_t k = ftok(PATH_NAME, PROJ_ID);
    assert(k != -1);

    Log("create key done", Debug) << " server key : " << TransToHex(k) << endl;

    // 2. 创建共享内存 -- 建议要创建一个全新的共享内存 -- 通信的发起者
    int shmid = shmget(k, SHM_SIZE, IPC_CREAT | IPC_EXCL | 0666); //
    if (shmid == -1)
    {
        perror("shmget");
        exit(1);
    }
    Log("create shm done", Debug) << " shmid : " << shmid << endl;


    // 3. 将指定的共享内存,挂接到自己的地址空间
    char *shmaddr = (char *)shmat(shmid, nullptr, 0);
    Log("attach shm done", Debug) << " shmid : " << shmid << endl;

    
    int fd = OpenFIFO(FIFO_NAME, READ);
    for(;;)
    {
        Wait(fd);

        // 临界区
        printf("%s\n", shmaddr);
        if(strcmp(shmaddr, "quit") == 0) break;
        // sleep(1);
    }
    // 4. 将指定的共享内存,从自己的地址空间中去关联
    int n = shmdt(shmaddr);
    assert(n != -1);
    (void)n;
    Log("detach shm done", Debug) << " shmid : " << shmid << endl;


    // 5. 删除共享内存,IPC_RMID即便是有进程和当下的shm挂接,依旧删除共享内存
    n = shmctl(shmid, IPC_RMID, nullptr);
    assert(n != -1);
    (void)n;
    Log("delete shm done", Debug) << " shmid : " << shmid << endl;

    CloseFifo(fd);
    return 0;
}

  上述共享内存代码是结合了命名管道通信进行了访问控制文章来源地址https://www.toymoban.com/news/detail-703805.html

到了这里,关于【Linux从入门到精通】通信 | 共享内存(System V)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【探索Linux】—— 强大的命令行工具 P.15(进程间通信 —— system V共享内存)

    在多进程编程中,进程间通信(IPC)是一项关键技术,它使得不同的进程能够相互交换数据和协调行为。而在众多的IPC机制中,System V共享内存是一种高效且强大的通信方式。通过使用共享内存,我们可以将数据从一个进程快速地传递给另一个进程,避免了复制数据的开销,

    2024年02月05日
    浏览(62)
  • 【Linux】system V 共享内存

    system V 是一套标准,独立于文件系统之外的,专门为了通信设计出来的模块 让两个毫不相关的进程看到同一份资源 第一阶段原理 进程A和进程B都通过自己的页表映射到物理内存中的特定区域,进而找到该进程匹配的代码和数据 为了让进程A和进程B通信, 前提是两者要看到同

    2023年04月18日
    浏览(32)
  • 【Linux初阶】system V - 共享内存

    共享内存区是最快的IPC(进程间通信)形式 。一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据。 在物理内存中 申请一块空间 ,将创建好的 内存映射进进程的地址空

    2024年02月13日
    浏览(35)
  • [Linux打怪升级之路]-system V共享内存

    前言 作者 : 小蜗牛向前冲 名言 : 我可以接受失败,但我不能接受放弃   如果觉的博主的文章还不错的话,还请 点赞,收藏,关注👀支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 本期学习目标:认识什么是 system V共享内存,认识共享内存的接口函数,学会

    2024年02月08日
    浏览(46)
  • 【Linux】System V 共享内存、消息队列、信号量

    🍎 作者: 阿润菜菜 📖 专栏: Linux系统编程 System V 共享内存是一种进程间通信的机制,它允许多个进程 共享一块物理内存区域 (称为“段”)。System V 共享内存的优点是效率高,因为进程之间不需要复制数据;缺点是 需要进程之间进行同步,以避免数据的不一致性 。 共

    2024年02月04日
    浏览(50)
  • Linux进程通信——共享内存

    两个进程的PCB创建虚拟地址空间然后映射到物理内存中,每个进程因为是独立的,所以在物理内存中的地址也不同。 那么共享内存是怎么做到的呢? 首先先在物理内存中申请一块内存。 然后讲这块内存通过页表映射分别映射到这两个进程的虚拟地址空间内,让这两个进程都

    2024年02月01日
    浏览(51)
  • 【Linux】进程通信 — 共享内存

    上一章我们由进程通信,引入并讲述了管道,匿名管道和命名管道和匿名管道。本章我们将继续讲解进程通信的另一种方式,通过共享内存的方式来进行进程间的通信。还要学习几个系统调用接口,并用代码实现两个进程通过共享内存来进行通信。目标已经确定,接下来就要

    2024年02月15日
    浏览(44)
  • Linux——进程通信之共享内存

    目录 一.  回顾上文 二.共享内存 1.定义 2.特点: 3.实现步骤: 如下为成功链接共享内存使用权的完整步骤: 4.函数介绍         4.1shmget函数         4.1.2参数介绍                4.2ftok函数:         4.2.1参数介绍                 关于ftok(); shmget();函数的

    2024年02月12日
    浏览(54)
  • system-v IPC共享内存通信

    目录 system v IPC简介 共享内存需要用到的函数接口 shmget函数--获取对象ID shmat函数--获得映射空间 shmctl函数--释放资源 共享内存实现思路 注意 消息队列、共享内存和信号量统称为system v IPC(进程间通信机制),V是罗马数字5,是UNIX的ATT分支的其中一个版本,一般称它们为IPC对象

    2024年04月26日
    浏览(50)
  • (26)Linux 进程通信之共享内存(共享储存空间)

    共享内存是System V版本的最后一个进程间通信方式。 共享内存,顾名思义就是允许两个不相关的进程访问同一个逻辑内存,共享内存是两个正在运行的进程之间共享和传递数据的一种非常有效的方式。不同进程之间共享的内存通常为同一段物理内存。进程可以将同一段物理内

    2024年01月16日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包