Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【Linux篇章】进程通信黑科技:System V 共享内存,开启进程间通信的星际数据通道!

【Linux篇章】进程通信黑科技:System V 共享内存,开启进程间通信的星际数据通道!

作者头像
羑悻的小杀马特.
发布于 2025-04-30 02:06:31
发布于 2025-04-30 02:06:31
12500
代码可运行
举报
文章被收录于专栏:杀马特杀马特
运行总次数:0
代码可运行

在计算机系统里,进程就像一个个独立工作的小员工,各自完成自己的任务。但有时候,这些小员工之间需要交流信息、共享数据,这就涉及到进程间通信(IPC)。System V 共享内存就是进程间通信的一种强大方式,下面就带大家了解一下它的奥秘。

一·什么是共享内存:

本质:也是让不同进程看到同一份资源。

1.1共享内存概念及外观:

想象有一个公共的大黑板,不同的进程都可以在这个黑板上写东西和看东西,这个大黑板就类似于 System V 共享内存。它允许不同的进程访问同一块物理内存区域,进程可以直接在这块内存中读写数据,而不需要进行繁琐的数据复制操作,这使得数据的传输速度非常快。(shm -->system shared memory)

那么此时就需要“先描述,后组织”;把这些shm用各自的结构体给组织起来(这里我们可以认为是链表然后有多个进程用它;那么就会存在引用计数(nattach)来明确这块共享内存当没有进程使用的时候就销毁它;后面我们会讲如何操作)。

这里我们的动态库加载也是用的共享内存但是是mmap映射方式罢了(了解即可)。

1.2共享内存数据结构:

这里我们可以用man shmctl 这个指令来查看:

下面我们就来看一下上面说的描述共享内存的结构体吧:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
struct shmid_ds {
               struct ipc_perm shm_perm;    /* Ownership and permissions */
               size_t          shm_segsz;   /* Size of segment (bytes) */
               time_t          shm_atime;   /* Last attach time */
               time_t          shm_dtime;   /* Last detach time */
               time_t          shm_ctime;   /* Creation time/time of last
                                               modification via shmctl() */
               pid_t           shm_cpid;    /* PID of creator */
               pid_t           shm_lpid;    /* PID of last shmat(2)/shmdt(2) */
               shmatt_t        shm_nattch;  /* No. of current attaches */
               ...
           };
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
struct ipc_perm {
               key_t          __key;    /* Key supplied to shmget(2) */
               uid_t          uid;      /* Effective UID of owner */
               gid_t          gid;      /* Effective GID of owner */
               uid_t          cuid;     /* Effective UID of creator */
               gid_t          cgid;     /* Effective GID of creator */
               unsigned short mode;     /* Permissions + SHM_DEST and
                                           SHM_LOCKED flags */
               unsigned short __seq;    /* Sequence number */
           };

也就是说当我们创建好共享内存的话;以及然后与想要通信的进程关联就需要填充这些数据等。

二·为什么需要共享内存:

传统的进程间通信方式,比如管道、消息队列等,在数据传输时需要将数据从一个进程的内存复制到内核空间,再从内核空间复制到另一个进程的内存,这个过程比较耗时。而共享内存直接让多个进程访问同一块内存,避免了多次数据复制,大大提高了数据传输的效率。就好比大家都围在一个大黑板前交流,比一个人把信息写在纸条上,再传递给另一个人要快得多。

共享内存区是最快的IPC形式。⼀旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执⾏进⼊内核的系统调⽤来传递彼此的数据。

三·共享内存相关使用的指令及函数:

3.1相关指令:

3.1.1查看共享内存:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ipcs -m + shmid(共享内存编号)

3.1.2删除共享内存:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ipcrm -m + shmid(共享内存编号)

下面我们删除shmid为36的这个共享内存:

这样就被销毁了。

这里我们只能用shmid来操控共享内存而不能是key(后面会说);而且进程退出!=shm回收;还是需要手动指令回收或者函数来回收。

3.1.3 删除全部共享内存:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ipcrm -a 

使用 ipcrm -a 可以一次性删除系统中所有类型的 IPC 资源。

不过需要注意的是,执行该命令需要有足够的权限。通常情况下,普通用户只能删除自己创建的 IPC 资源,而要删除系统中所有的 IPC 资源,需要以超级用户(root)的身份执行该命令,所以实际操作中一般会这样使用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
sudo ipcrm -a

ipc指令拓展:

删除所有消息队列:使用 ipcrm -q 选项,命令格式为 sudo ipcrm -q (需 root 权限)。 删除所有共享内存段:使用 ipcrm -m 选项,命令格式为 sudo ipcrm -m (需 root 权限)。 删除所有信号量集:使用 ipcrm -s 选项,命令格式为 sudo ipcrm -s (需 root 权限)。

3.2使用共享内存函数:

3.2.1ftok:

即file to key :

生成特定的key作为shmget创建的共享内存的唯一性标识(无其他作用是标识唯一性)。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 #include <sys/types.h>
 #include <sys/ipc.h>

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

pathname∶这是一个指向现有文件或目录的路径名的指针。该文件或目录必须存在且调用进程对其有访问权限,因为ftok会使用该文件的索引节点号(inode number)来生成键值。

proj_id:这是一个用户指定的项目ID,它是一个非零的8位整数(取值范围是1-255)。ftok会将该值的低8位与pathname对应的文件的索引节点号组合起来生成最终的键值。

我们需要第一个数据需要的是存在的路径(因为会借助inode等来通过一定方式生成key);第二个是一个八位的数字。

成功就返回32位的键值;失败就返回-1。

3.2.2shmget:

即shm get(内存中创建共享内存):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 #include <sys/ipc.h>
 #include <sys/shm.h>

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

key:这个共享内存段名字。 size:共享内存⼤⼩。 shmflg:由九个权限标志构成,它们的⽤法和创建⽂件时使⽤的mode模式标志是⼀样的取值为IPC_CREAT: 共享内存不存在,创建并返回;共享内存已存在,获取并返回。 取值为IPC_CREAT | IPC_EXCL: 共享内存不存在,创建并返回;共享内存已存在,出 错返回。 返回值:成功返回⼀个⾮负整数(shmid),即该共享内存段的标识码;失败返回-1。

对于size:以4kb倍数开辟:但是如果传入的不是;它也会开辟4kb倍数;只是给用户的还是他输入的值;其实开的多只是不允许访问 。

当然了shmflg也可以配合权限掩码使用;就是这块共享内存允许谁操作:

3.2.3shmat:

即shm attach(共享内存关联):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <sys/types.h>
  #include <sys/shm.h>

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

shmid: 共享内存标识 shmaddr:指定连接的地址(默认传nullptr) shmflg:它的两个可能取值是SHM_RND和SHM_RDONLY(默认0:可读可写) 返回值:成功返回⼀个指针,指向共享内存第⼀个节;失败返回-1(void*强转)

对于传入的shmflg是SHM_RDONLY就是只读了(映射到的虚拟内存空间);不过;我们这个参数一般都是默认0。

3.2.4shmdt:

即shm detach(取消关联):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 #include <sys/types.h>
 #include <sys/shm.h>

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

shmaddr: 由shmat所返回的指针返回值:成功返回0;失败返回-1 注意:将共享内存段与当前进程脱离不等于删除共享内存段(还是需要用shmctl或者ipcrm -m来删除的(删除前必须确保已经detach了))

进程直接异常退出等它不会减少nattch;只有手动去shmdt才行否则后序的shmctl的rmid会出问题 。

3.2.5shmctl:

即shm control (控制共享内存:分为删除,获取信息,改变权限):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 #include <sys/ipc.h>
  #include <sys/shm.h>

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

shmid:由shmget返回的共享内存标识码。 cmd:将要采取的动作(有三个可取值) buf:指向⼀个保存着共享内存的模式状态和访问权限的数据结构(默认传nullptr;不关心这个输出型参数) 返回值:成功返回0;失败返回-1。

下面我们基于写好的共享内存创建的代码来验证一下(利用上面所展示的共享内存的数据结构的结构体):

IPC_RMID这里就不需要了(每次建立共享内存后就需要删除;我们看后面实现代码效果就好了)

来演示下剩下的两个:

IPC_STAT(status):

首先在我们的shm类中添加成员函数:

下面我们从外部查看一下是否能把这个共享内存的信息放到传入的ds中:

也是显示出来的。

IPC_SET:

这里注意共享内存权限是只能修改:

我们的目的是通过传入更改共享内存的权限:mode。

这里我们默认创建的权限掩码是0666;我们打算把它修改成0006:

运行一下:

也是可以修改的。

四·共享内存优缺点:

4.1优点:

速度快:避免了数据的多次复制,数据传输效率高。

使用方便:进程可以像操作普通内存一样操作共享内存。

4.2缺点:

同步问题:由于多个进程可以同时访问共享内存,可能会出现数据竞争的问题。比如,一个进程正在写入数据,另一个进程同时读取数据,可能会导致数据不一致。这就需要使用其他的同步机制,如信号量,来保证数据的一致性。

管理复杂:需要手动管理共享内存的创建、连接、分离和删除,容易出现内存泄漏等问题。System V 共享内存是一种强大的进程间通信方式,它为进程之间的高效数据共享提供了可能。但在使用时,需要注意同步和管理问题,以确保系统的稳定性和数据的一致性。通过合理使用 System V 共享内存,我们可以让不同的进程更好地协作,共同完成复杂任务。

不同步的例子:

也就是说shm不会阻塞住它是一直读的;读取的内容可能不是我们期望的;比如:我们想让它读一句话;你好;我走了。 然而如果没控制好让它什么时候读它就有可能只读你好;之后才会说我走了;不连贯。

简单来说就是:速度快;不需要等待;写到虚拟内存空间就马上读;但是正是因为这一点;导致读写可能会出现一些错误(不是我们所需的)--->无读写的同步性;只能自己控制;以及管理起来还是比管道要困难;即对共享内存里的数据无保护机制。

那么我们如何用最简单的方法增强这种同步性;让它读取我们需要的内容呢?

那就是我们之前学的命名管道了(传送门:【Linux篇章】进程通信黑科技:匿名管道的暗码传递与命名管道的实名使命-CSDN博客

可以使用命名管道:当我们写进程想让它读的时候就从管道写入;当读进程发现管道有数据时候才会读shm内容(但是有很多细节注意先后顺序; sleep时候的时间等;一定控制好让它读完一条再写{而不是读这一条呢;然后shm内又被写端写入了})

五·共享内存重要小tip:

①shm不随进程属于内核;也就是进程终止它仍旧存在;受内核管控必须指令清除或者代码清除。 (这也就是共享内存的特性了)

②与文件相关但又不强相关: shmid fd但是文件fd关了可以重新再开始而shm清除后下一个后从它此时的mid累加。

下面我们演示一下:

我们知道如果是文件:比如创建一个fd就是3的话删除它再传进还是3;但是共享内存的shmid就不一样了;没有这种特性。

此时我们创建了一个共享内存shmid为37;下面我们把它删除再创建一个。

发现变成了38而不是像我们文件一样是37。

③其次和管道不同的是:管道需要掉系统open等接口进行操作;而shm直接映射到进程的虚拟地址空间这样用户就可以直接使用(语言封装的函数等)

对应管道操作;我们不难发现它使用了open;write等系统调用:

但是对应共享内存的话我们直接就用的是封装好的用户层参数直接向着虚拟内存空间操作:

因为我们如果共享内存完成映射后;就到了进程的虚拟内存空间;这不就类似我们以前语言函数操作创建变量的形式了;但是如果是管道的话它是一个特殊文件(我们需要用系统的接口去执行)。

④key在用户层只是区分不同shm的;用户还是用shmid来操作shm。

我们用ftok特殊方式生成的key只是共享内存的唯一标识;方便找到同一块内共享内存以及Os管理共享内存;无其他的用处;使用共享内存给用户层的还是shmid(类似文件的fd)。

⑤这里说一下;如果是进程异常退出导致的共享内存没有删除或者有nattch的时候把它删除(ipcrm或者shmctl)那么之后还是会有个dest标记如:

(ipcrm -m 或者shmctl -->如果有关联它们都会标记dest(待删除状态)【表示这块内存不能再被使用了】) 但是先前关联过的进程还是可以用;只是后面无法再与它关联;当与它关联的都shmdt掉;就会被立即释放。

共享内存底层大致是怎么样实现的呢?

下面我们粗略的说一下:

首先我们调用的是shmget;它会在共享内存的那个结构体有个文件指针;开辟一个struct_file以及对应的缓冲区(只不过连接到了物理内存而不是磁盘);然后我们调用了shmat完成虚拟映射:其实就是把进程中mm结构体里的vm结构体的vm*file指向这个struct_file;此时就相当于把vm中虚拟地址的start和and指向了这个块缓冲区(这里可以理解成完成了我们对应页表的映射;也就是我们只需要用语言封装的函数向虚拟地址指向的位置进行操作;那么它就会自己转化到缓冲区写入然后到物理内存--->其实就是省去了对文件的系统性操作)

六·基于共享内存实现的进程通信:

下面我们基于使用上面的共享内存来完成对进程间交流代码的实现:

6.1无手动输入的通信:

下面我们基于命名管道改进它的非同步性的通信方式的代码(这里我们要求client进行写入aa cc...)然后让server读取;而不是当client写了一个server就读(a aa aaac这样的)。然后等client端写完就给server一个命令告诉它写完了;server就可以关闭命名管道以及回收共享内存了(这里一定要注意的是server和client谁先时候执行代码的时间问题;否则将会出现bug

下面我们运行一下:

下面有一些细节问题就是client和server这两个端怎么设计交流以及命名管道和共享内存如何创建的细节问题(多个初始化及析构顺序问题)请看代码:

define.hpp:

这里因为fifo.hpp以及shm.hpp都会用到这个宏;不让它重复使用直接搞成头文让它只包含一次就好。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#pragma once
#define EXIT(e) do { perror(e);exit(EXIT_FAILURE);}while(0)

fifo.hpp:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#pragma once  
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include<string>
using namespace std; 


class cnpipe{
   public:
    cnpipe(const string & path,const string & name):_path(path),_name(name)
     {   _pfname=_path+"/"+_name;
        umask(0);
        int n=mkfifo(_pfname.c_str(),0666);
          if (n != 0)
        {
          EXIT("mkdir");
           
        }
        
     }
     ~cnpipe(){
        int u=unlink(_pfname.c_str());
        if(u==0) std::cout<<"成功删除管道"<<std::endl;
         else EXIT("unlink");
       
     }
    private:
     
   string _path;
    string _name;
    string _pfname;
};
class oppipe{
   

    public:
    oppipe(const string & path,const string & name):_path(path),_name(name){
        _pfname=_path+"/"+_name;
    }

       void openw(){
        _fd=open(_pfname.c_str(),O_WRONLY);
        std::cout<<"openw success"<<std::endl;//服务端也就是管道读端没有进入则一直堵塞
        if (_fd < 0)
     {
         EXIT("openw");
     }
       }
      void openr(){
        _fd=open(_pfname.c_str(),O_RDONLY);
        std::cout<<"openr success"<<std::endl;//客户端也就是管道写端没有进入则一直堵塞
         if (_fd < 0)
      {
          EXIT("openr");
      }
      }
     void wakeup_server(){
          // while(1){
          //   std::string mess;
          //  std:: getline(std::cin,mess);
          // int n=write(_fd,mess.c_str(),mess.size());
          // if(n<0) EXIT("pwrite");
          // }
         char ch ='a';
         int n=write(_fd,&ch,1);
       
     }
     void exit_server(){
        char ch ='e';
         int n=write(_fd,&ch,1);
     }
     bool wait_client(){
        // while(1){
        //     char buff[1024]={0};
        //    int n= read(_fd,buff,sizeof(buff)-1);
        //  if(n>0) std:: cout<<"客户说:"<<buff<<std::endl;
        //  else if(n==0) {cout<<"client exit"<<endl; break;}
        // else  EXIT("pread");
        // }
         while(1){
         char buff[1024]={0};
           char ret;
        int n= read(_fd,&ret,1);
         if(ret=='a') return 1;
         else if(ret=='e') return 0;
         else{}
         }
         
        
    }
  void  Close(){
    if(_fd>0) close(_fd);
    }

    private:
    string _path;
    string _name;
    string _pfname;
    int _fd;

};

shm.hpp:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#pragma once
#include <iostream>
#include <cstdio>
#include <string>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#define projid 0x66
#define pathname "."
#define USER "user"
#define CREATER "creater"
using namespace std;


class shm{
public:
     shm(const string &pn, int pd,const string &name,int sz=4097):_name(name),_size(sz)
           {
            _key=ftok(pn.c_str(),pd);
            if(_name==USER) {  get(); }
            else if(_name==CREATER) {  create();}
            else{}
            attach();
           }

         void get(){
            corgshm(IPC_CREAT|0666);
         }

         void create(){
            corgshm(IPC_CREAT|IPC_EXCL|0666);
         }

         int sz(){
            return _size;
         }

         void * address(){
            return _mem_address;
         }
       void  getdata
       (struct shmid_ds *pds){
             shmctl(_shmid,IPC_STAT,pds);
         }
         void modifyshm(struct shmid_ds *pds){
             shmctl(_shmid,IPC_SET,pds);
               
         }
         

    ~shm(){
        int n=shmdt(_mem_address);
        if(n==-1) EXIT("shmdt");
       if(_name==CREATER) {
        destroy();
        cout<<"~shm success"<<endl;
    }
    }

private:

     void attach(){
         _mem_address=shmat(_shmid,nullptr,0);
         if((long long)_mem_address==-1) EXIT("shmat");
         cout<<"shmat success"<<endl;
     }

     void  corgshm(int k){
       int n= shmget(_key,_size,k);
       if(n==-1) EXIT("shmget");
       _shmid=n;
        cout<<"shmget sucess"<<endl;
      }

      void destroy(){
         int n=shmctl(_shmid,IPC_RMID,nullptr);
         if(n==-1) EXIT("shmctl"); 
         cout<<"shmctl success"<<endl;
      }
     int _key;
     int _shmid;
     string _name;
     int _size;
     void * _mem_address;

};

client.cc:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include"define.hpp"
#include"shm.hpp"
#include"fifo.hpp"

int main(){
    shm sm(pathname,projid,USER);
   oppipe op(".","ff");
   op.openw();
    char*as=(char *)sm.address();
    for(char ch='a';ch<='z';ch+=2){
        sleep(2);
        as[ch-'a']=ch;
        sleep(1);
        as[ch-'a'+1]=ch;
        as[ch+2]=0;
        op.wakeup_server();
    }
    op.exit_server();
    return 0;
    

}

server.cc:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include"define.hpp"
#include"shm.hpp"
#include"fifo.hpp"
int main(){
    shm sm(pathname,projid,CREATER);
    struct shmid_ds ds;
    //测试IPC_STAT:
    // sm.getdata(&ds);
    // cout<<ds.shm_segsz<<endl;
    // cout<<ds.shm_atime<<endl;
    // 测试IPC_SET(只能修改perm):
    // ds.shm_perm.mode=0006;
    // sm.modifyshm(&ds);
    // sleep(4);




    cnpipe cp(".","ff");
    oppipe op(".","ff");
    op.openr();
    char*as=(char *)sm.address();
    while(1){
        if(op.wait_client()){
            printf("%s\n",as);
        }
        else break;
    }
    op.Close();

    return 0;
}

Makefile:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
.PHONY:all
all:client server
client:client.cc
	g++ -o $@ $^ -std=c++11
server:server.cc
	g++ -o $@ $^ -std=c++11

.PHONY:clean
clean:
	rm -f client server

6.2访问控制板的通信:

下面我们只需要修改一下client端就可以了;让它直接访问控制板;我们约定当client端输入exit就代表退出(此时server端收到命令直接销毁管道和共享内存即可)其他代码不变就不展示了。

运行一下:

更改后的client.cc:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include"define.hpp"
#include"shm.hpp"
#include"fifo.hpp"

int main(){
    shm sm(pathname,projid,USER);
   oppipe op(".","ff");
   op.openw();
    char*as=(char *)sm.address();
    // for(char ch='a';ch<='z';ch+=2){
    //     sleep(2);
    //     as[ch-'a']=ch;
    //     sleep(1);
    //     as[ch-'a'+1]=ch;
    //     as[ch+2]=0;
    //     op.wakeup_server();
    // }
    while(1){
         string s;
         getline(cin,s);
         if(s=="exit") break;
        char buff[4097]={0};
        int i=0;
        for(auto a:s) buff[i++]=a;
      snprintf(as,sm.sz(),"%s\n",buff);
      op.wakeup_server();  
    }
    op.exit_server();
    return 0;
    

}

七.小结:

本次System V 共享内存解说就分享到此;期待我们在下一次Linux篇章再次相遇;感谢阅读。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-04-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Linux进程通信--共享内存
共享内存区是最快的IPC形式。一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据。
南桥
2024/07/26
3910
Linux进程通信--共享内存
【Linux】IPC 进程间通信(二)(共享内存)
🚀 共享内存是一种进程间通信(IPC)机制,它允许多个进程直接访问同一块内存区域,从而实现高效的数据交换。
IsLand1314
2024/11/19
2940
【Linux】IPC 进程间通信(二)(共享内存)
进程间通信(二)/共享内存
要实现进程间通信,其前提是让不同进程之间看到同一份资源。所谓共享内存,那就是不同进程之间,可以看到内存中同一块资源,这就是共享内存的概念。
二肥是只大懒蓝猫
2023/03/30
9630
进程间通信(二)/共享内存
Linux进程间通信【共享内存】
共享内存出自 System V 标准,是众多 IPC 解决方案中最快的一种,使用共享内存进行通信时,不需要借助函数进入内核传递数据,而是直接对同一块空间进行数据访问,至于共享内存是如何使用的、通信原理是怎么实现的、以及共享内存+命名管道的组合通信程序该如何实现,都将在本文中解答
北 海
2023/07/01
5970
Linux进程间通信【共享内存】
【Linux】进程间通信(命名管道、共享内存、消息队列、信号量)
命名管道是通过文件路径让不同进程看到同一份资源。 命名管道可以让两个毫不相干的进程进行进程间通信。
秦jh
2024/10/29
2860
【Linux】进程间通信(命名管道、共享内存、消息队列、信号量)
【Linux】从零开始认识进程间通信 —— 共享内存
吃苦受难绝不是乐事一桩,但是如果您恰好陷入困境,我很想告诉您:“尽管眼前十分困难,可日后这段经历说不定就会开花结果。”请您这样换位思考、奋力前行。
叫我龙翔
2024/06/02
3840
【Linux】从零开始认识进程间通信 —— 共享内存
【Linux】「共享内存揭秘」:高效进程通信的终极指南
探索Python数据结构与算法:解锁编程的无限可能:https://cloud.tencent.com/developer/article/2471556
Yui_
2024/11/27
4080
【Linux】「共享内存揭秘」:高效进程通信的终极指南
【Linux】进程间通信——共享内存
共享内存(Shared Memory)是一种 进程间通信(IPC) 机制,允许多个进程共享同一块物理内存,从而提高数据交换效率。相比其他 IPC 方式(如管道、消息队列等),共享内存具有 速度快、低开销 的优势,因为数据直接存储在内存中,而无需通过内核进行数据拷贝。
用户11305458
2025/02/28
3630
【Linux】进程间通信——共享内存
【Linux】system V进程间通信——共享内存、消息队列、信号量
进程具有独立性:内核数据结构包括对应的代码、数据与页表都是独立的。OS系统为了让进程间进行通信:1.申请一块空间 2.将创建好的内存映射进进程的地址空间。共享内存让不同的进程看到同一份的资源就是在物理内存上申请一块内存空间,如何将创建好的内存分别与各个进程的页表之间建立映射,然后在虚拟地址空间中将虚拟地址填充到各自页表的对应位置,建立起物理地址与虚拟地址的联系。
平凡的人1
2023/10/15
4100
【Linux】system V进程间通信——共享内存、消息队列、信号量
【Linux进程间通信】深入探索:Linux下的命名管道与System V共享内存
🔍前言:在Linux操作系统中,进程间通信(IPC)是一个至关重要的概念,它允许不同的进程之间进行数据交换和同步。随着现代操作系统的日益复杂,进程间通信的重要性也日益凸显。在众多IPC机制中,命名管道和System V共享内存无疑是两种最为常见且强大的工具
Eternity._
2024/10/10
2490
【Linux进程间通信】深入探索:Linux下的命名管道与System V共享内存
[操作系统] 进程间通信:system V共享内存
System V 是UNIX操作系统的一个版本,它定义了一系列的标准,包括进程间通信(IPC)的标准。Linux操作系统的内核实现了 <font style="color:rgb(6, 6, 7);">System V</font> 定义的IPC标准,并为此专门设计了一个模块来处理进程间的通信。进程间通信(IPC)的核心目的是允许不同的进程能够访问和操作同一份资源。这样,进程之间就可以通过共享资源来交换信息。不同的IPC机制可能在接口和原理上有相似之处,使得开发者可以更容易地理解和使用这些机制。
DevKevin
2025/05/30
170
[操作系统] 进程间通信:system V共享内存
【Linux】进程间通信——System V共享内存
  System V是一种在Linux系统中用于进程间通信(IPC)的机制。它提供了几种不同的通信方式,包括共享内存、消息队列和信号量。以下是关于Linux进程间通信System V共享内存的详细解释:
大耳朵土土垚
2024/12/09
2230
【Linux】进程间通信——System V共享内存
【Linux】进程间通信(命名管道、共享内存、消息队列、信号量)
回车之后管道不会关闭,在终端2查看可以发现他的内存大小仍然是0,当我们在管道2打印出内容后,管道就自动关闭了
用户11036582
2024/11/05
2190
【Linux】进程间通信(命名管道、共享内存、消息队列、信号量)
进程间通信方式——共享内存「建议收藏」
共享内存就是允许两个或多个进程共享一定的存储区。就如同 malloc() 函数向不同进程返回了指向同一个物理内存区域的指针。当一个进程改变了这块地址中的内容的时候,其它进程都会察觉到这个更改。因为数据不需要在客户机和服务器端之间复制,数据直接写到内存,不用若干次数据拷贝,所以这是最快的一种IPC。
全栈程序员站长
2022/09/27
1.3K0
【Linux】进程间通信>管道&&共享内存&&消息队列&&信号量详解
vscode远程连接指南:VScode远程连接虚拟机(ubuntu系统)_vscode连接ubuntu-CSDN博客
用户10925563
2024/06/04
2240
【Linux】进程间通信>管道&&共享内存&&消息队列&&信号量详解
Linux 进程间通信 : 共享内存(上)
邹立巍
2017/07/26
11.5K3
System V IPC 共享内存详解
​ 这里我们介绍的这种通信方式也就是 system V IPC 在我们后面的使用和日常见到的其实并不多,但是包括其中的共享内存、消息队列、信号量,我们如果了解共享内存其原理的话,能够更好的帮助我们了解之前我们学过的进程地址空间的概念!
利刃大大
2023/04/12
1.1K0
System V IPC 共享内存详解
【Linux】system V 共享内存
system V 是一套标准,独立于文件系统之外的,专门为了通信设计出来的模块 让两个毫不相关的进程看到同一份资源
lovevivi
2023/10/16
4230
【Linux】system V 共享内存
【Linux篇】共享内存实战:打造高性能服务端与客户端通信的终极指南(赋源码)
共享内存是一种高效的进程间通信(IPC)方式,允许多个进程访问同一块内存区域。通过共享内存,进程之间可以直接读写数据,而无需经过操作系统的中介,从而减少了上下文切换的开销。在服务端和客户端通信中,服务端通常会创建共享内存并将数据写入该区域,客户端可以直接读取该数据。由于共享内存不需要通过管道、套接字等其他通信方式,因此在高性能应用中非常有用。实现简单的服务端与客户端通信时,服务端负责创建并初始化共享内存,客户端则连接到该内存并读取或写入数据。这样,双方可以通过共享内存高效地交换信息。
熬夜学编程的小王
2025/04/25
1650
【Linux】systemV共享内存
操作系统在物理内存上申请一块空间,然后将申请到的空间通过页表映射到进程地址空间mm_struct的共享区中,然后返回虚拟地址供程序使用,如果多个进程申请的是同一块物理空间,那么它们就可以进行通信 由于同一时间可能有多组进程进行通信,所以系统当中可能存在多个共享内存块,所以操作系统要把这些内存管理起来,所以内核中会有一个结构体来描述共享内存
s-little-monster
2025/03/25
2421
【Linux】systemV共享内存
推荐阅读
相关推荐
Linux进程通信--共享内存
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验