Linux进程通信——共享内存、消息队列和信号量

共享内存通信

共享内存是 Linux 下速度最快的进程间通信方式,核心思想是:在物理内存中开辟一块共享内存块,多个进程通过页表映射,将这块物理内存挂载到各自独立的虚拟地址空间中 。进程直接读写虚拟地址,就等价于操作同一块物理内存,省去内核缓冲区拷贝,通信效率极高。

⚠️ 重要缺陷:共享内存没有自带同步互斥机制 。多个进程同时读写共享区域会产生竞态问题,需要额外搭配信号量、互斥锁来控制访问时序。
创建时会使用的函数:
获取 shmid: shmget(key_t key(用户给的键值), int size(内存块大小), shmflag(IPC_CREAT|IPC_EXCL|0666))
挂接: shmat(shmid, nullptr, 0); 返回值为起始虚拟空间地址
解除挂接: shmdt(shmaddr(起始虚拟空间地址))
删除内存块: shmctl(_shmid, IPC_RMID, nullptr)

下面是小demo:
基本结构

cpp 复制代码
#pragma once
#include<iostream>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/types.h>
#include<cstdio>
#include<unistd.h>
#include<cstring>


#define PATHNAME  "/tmp"
#define proj_id 066
#define SIZE 128



class shared_memory
{
public:
    shared_memory()
    :_shmid(-1),
    _size(SIZE),
    _start_shmaddr(nullptr)
    {}
    ~shared_memory(){}
    private:
    int _shmid;//给用户使用的id,跟fd文件描述符类似功能都是供给用户使用
    int _size;//内存块大小
    void* _start_shmaddr;//映射到虚拟地址空间的共享区起始地址
    
};

创建内存块和获取:

ftok()函数是根据路径加用户给的随便的八进制数字组成的key(标识内存块的唯一值,跟inode的作用类似)

cpp 复制代码
//创建共享内存块
    void Create()
    {
        _shmid = Get_shmid(IPC_CREAT|IPC_EXCL|0666);
       if(_shmid < 0)
       {
            std::cerr << "file already exists" << std::endl;
            exit(1);
       }
        std::cout << "create success!!! shmid = " << _shmid << std::endl;
    }
    void Get()
    {
         _shmid = Get_shmid(IPC_CREAT);
    }
     int Get_key()
    {
        key_t key =  ftok(PATHNAME,proj_id);
        if(key < 0)
        {
         std::cerr << "key already exists" << std::endl;
        exit(1);
        }
        printf("key:%d\n",key);
        return key;
    }
    int Get_shmid(int shmflag)
    {
         key_t key = Get_key();
        return shmget(key,SIZE,shmflag);
       
    }

挂接、解挂接和删除:

cpp 复制代码
//挂接到进程中
    void sh_attach()
    {
        _start_shmaddr = shmat(_shmid,nullptr,0);
        if(_start_shmaddr == (void*)(-1))
        exit(1);
        std::cout << "进程挂接共享内存块成功!" << std::endl;
    }
    //解除进程挂接
    void sh_Dattach()
    {
        int n = shmdt(_start_shmaddr);
    }
    //删除内存块
    void Delete()
    {
        int n = shmctl(_shmid,IPC_RMID,nullptr);
    }

消息队列通信(了解即可)

消息队列是另一种进程间通信方式,通过在内核中维护一个消息链表,进程间以「消息」为单位传递数据。相比共享内存,它自带一定的同步机制,但传输效率较低,适合传递小数据量、需要顺序保证的场景。这里仅作了解,重点掌握共享内存即可。

信号量(了解即可)

信号量主要用于解决共享内存的同步互斥问题,本质是一个计数器,通过 P 操作(申请资源,计数器减一)和 V 操作(释放资源,计数器加一)来保护临界区。它与共享内存搭配使用,这里仅需了解其作用即可,不必深入实现细节。后面有更好的信号量来搭配共享内存

相关推荐
小白的码BUG之路6 小时前
linux -- ssh两台机器相连
运维·服务器·ssh
聚美智数6 小时前
智能结构化识别-图片结构解析-图像结构化解析-照片结构化解析
android·java·数据库
缓慢更新7 小时前
表单引擎的存储建模:宽表与文档库的取舍
运维·服务器·网络·数据库·低代码·oracle·适配器模式
续写烂尾8 小时前
贴片 SD NAND、eMMC、TF 卡规格怎么定?硬件工程师选型清单
运维·服务器·网络
不昀8 小时前
网口Link Up后仍然掉线,怎样区分物理链路和数据通路问题?
linux·以太网
迪康妍妍8 小时前
终端管控实操:封堵网盘与IM外发通道的落地思路
运维·网络·安全·架构·安全性测试
sxgzzn8 小时前
如何选择合适的开关柜在线监测工具?
运维·重构·无人机·开关柜局放在线监测·光伏运维管理系统
Lhan.zzZ9 小时前
Qt WebEngineView 在 Linux 上无法加载网页:从“看不见 HTML“到“禁用沙箱“
linux·c++·qt
zxcvb1539 小时前
运维经验分享:监控网页更新内容的几种思路
运维
Fcy64810 小时前
Linux下 多路转接select详解
linux·select·多路转接