☰
第13讲:mmap实现进程间通信
2026/11/5 2:06:28 网站建设 项目流程

目录

  • 需求
  • 1. 代码
    • SharedMem.hpp
    • Server.cc
    • Client.cc
    • Makefile
  • 2. 控制结果
  • 3. 附录
    • 3-1 shm_open

需求

  • 使用进程间互斥锁、条件变量和mmap技术实现通信。
  • 控制通信逻辑,让目标进程按照我们的需要进行活动。
  • 代码为主,没有过多的理论,这里直接上代码。

1. 代码

SharedMem.hpp

#pragmaonce#include<iostream>#include<sys/mman.h>#include<semaphore.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>#include<unistd.h>#include<string.h>#include<pthread.h>#defineSIZE4096classSafeObj{public:SafeObj(){}voidInitObj(){// 初始化锁pthread_mutexattr_t mattr;pthread_mutexattr_init(&mattr);pthread_mutexattr_setpshared(&mattr,PTHREAD_PROCESS_SHARED);// 设置进程间共享pthread_mutex_init(&lock,&mattr);// 初始化条件变量pthread_condattr_t cattr;pthread_condattr_init(&cattr);pthread_condattr_setpshared(&cattr,PTHREAD_PROCESS_SHARED);// 设置进程间共享pthread_cond_init(&cond,&cattr);// 缓冲区清空memset(buffer,0,sizeof(buffer));}voidCleanupObj(){pthread_mutex_destroy(&lock);pthread_cond_destroy(&cond);}voidLockObj(){intn=::pthread_mutex_lock(&lock);(void)n;}voidUnlockObj(){intn=::pthread_mutex_unlock(&lock);(void)n;}voidWait(){intn=::pthread_cond_wait(&cond,&lock);(void)n;}voidSignal(){intn=::pthread_cond_signal(&cond);(void)n;}voidBroadCast(){intn=::pthread_cond_broadcast(&cond);if(n!=0)std::cerr<<"broadcast error"<<std::endl;elsestd::cerr<<"broadcast success"<<std::endl;}voidGetContent(std::string*out){*out=buffer;}voidSetContent(conststd::string&in){memset(buffer,0,sizeof(buffer));strncpy(buffer,in.c_str(),in.size());}~SafeObj(){}private:pthread_mutex_t lock;pthread_cond_t cond;charbuffer[SIZE];// 未来进程共享的数据区域};// 共享内存对象名必须以 / 开头,这是 shm_open 的约定#defineSHARED_MEMORY_FILE"/shm"#defineSHARED_MEMORY_SIZEsizeof(SafeObj)classMmapMemory{public:MmapMemory(conststd::string&file,intsize):_file(file),_size(size),_fd(-1),_mmap_addr(nullptr){}voidOpenFile(){_fd=::shm_open(_file.c_str(),O_CREAT|O_RDWR,0666);if(_fd<0){perror("shm_open");exit(1);}}voidTruncSharedMemory(){intn=ftruncate(_fd,_size);if(n<0){perror("ftruncate");exit(2);}}void*Mmap(){_mmap_addr=::mmap(nullptr,_size,PROT_READ|PROT_WRITE,MAP_SHARED,_fd,0);if(_mmap_addr==MAP_FAILED){perror("mmap");exit(3);}return_mmap_addr;}voidRemoveFile(){intn=::shm_unlink(_file.c_str());if(n<0){perror("shm_unlink");exit(4);}}void*MmapAddr(){return_mmap_addr;}~MmapMemory(){if(_fd>0){::close(_fd);std::cout<<"关闭mmap文件"<<std::endl;}intn=::munmap(_mmap_addr,_size);if(n==0){std::cout<<"munmap 完成"<<std::endl;}}private:int_fd;int_size;std::string _file;void*_mmap_addr;};classMmapMemoryServer:publicMmapMemory{public:MmapMemoryServer():MmapMemory(SHARED_MEMORY_FILE,SHARED_MEMORY_SIZE){MmapMemory::OpenFile();MmapMemory::TruncSharedMemory();MmapMemory::Mmap();obj=static_cast<SafeObj*>(MmapMemory::MmapAddr());obj->InitObj();}// 每个进程都有一次读取数据的机会voidRecvMessage(std::string*out){obj->LockObj();obj->Wait();obj->GetContent(out);obj->UnlockObj();}~MmapMemoryServer(){obj->CleanupObj();MmapMemory::RemoveFile();}private:SafeObj*obj;};classMmapMemoryClient:publicMmapMemory{public:MmapMemoryClient():MmapMemory(SHARED_MEMORY_FILE,SHARED_MEMORY_SIZE){MmapMemory::OpenFile();MmapMemory::Mmap();obj=static_cast<SafeObj*>(MmapMemory::MmapAddr());}voidSendMessage(conststd::string&in){obj->LockObj();obj->SetContent(in);// SafeSharedMemory::Signal(); // 唤醒进程obj->BroadCast();// 把他们全部叫醒,让他们自己判断,谁应该活动obj->UnlockObj();}~MmapMemoryClient(){}private:SafeObj*obj;};

Server.cc

#include"SharedMem.hpp"#include<sys/wait.h>#include<sys/types.h>voidActive(MmapMemoryServer&svr,std::string processname){std::cout<<"process is running: "<<processname<<std::endl;std::string who;while(true){svr.RecvMessage(&who);if(who==processname||who=="all"){std::cout<<processname<<" is active!"<<std::endl;}if(who=="end"){std::cout<<processname<<" is quit!"<<std::endl;break;}}}intmain(){MmapMemoryServer svr;for(inti=0;i<10;i++){pid_t id=fork();if(id==0){std::string name="process-"+std::to_string(i);Active(svr,name);exit(0);}}Active(svr,"process-main");for(inti=0;i<10;i++){wait(nullptr);}return0;}

Client.cc

#include"SharedMem.hpp"#include<string.h>intmain(){MmapMemoryClient cli;std::string who;while(true){std::cout<<"Please Enter# ";std::getline(std::cin,who);cli.SendMessage(who);if(who=="end"){break;}}return0;}

Makefile

.PHONY:all all:server client server:Server.cc g++ -o $@ $^ -lpthread -lrt -std=c++11 -g client:Client.cc g++ -o $@ $^ -lpthread -lrt -std=c++11 -g .PHONY:clean clean: rm -f server client

2. 控制结果

3. 附录

3-1 shm_open

NAME

shm_open,shm_unlink- create/open or unlink POSIX shared memory objects

SYNOPSIS
#include<sys/mman.h>#include<sys/stat.h>/* For mode constants */#include<fcntl.h>/* For O_* constants */intshm_open(constchar*name,intoflag,mode_tmode);intshm_unlink(constchar*name);

Link with-lrt.

官方说明

shm_open()creates and opens a new, or opens an existing, POSIX shared memory object. A POSIX shared memory object is in effect a handle which can be used by unrelated processes tommap(2)the same region of shared memory. Theshm_unlink()function performs the converse operation, removing an object previously created byshm_open().

The operation ofshm_open()is analogous to that ofopen(2).namespecifies the shared memory object to be created or opened. For portable use,a shared memory object should be identified by a name of the form /somename; that is, a null-terminated string of up toNAME_MAX(i.e., 255) characters consisting of an initial slash, followed by one or more characters, none of which are slashes.

  • name:共享内存对象的名称,类似于文件名。这个名称在文件系统中是不可见的,它只用于shm_open和其他相关函数来引用共享内存对象。名称必须符合路径名的构造规则。
  • oflag:打开标志,用于指定打开方式。它可以是以下值的按位或运算组合:
    • O_RDONLY:以只读方式打开共享内存对象。
    • O_RDWR:以读写方式打开共享内存对象。
    • O_CREAT:如果共享内存对象不存在,则创建它。如果已存在,则此标志无效(除非与O_EXCL一起使用)。
    • O_EXCL:与O_CREAT一起使用时,如果共享内存对象已存在,则shm_open调用失败。
    • O_TRUNC:如果共享内存对象存在且以读写方式成功打开,则将其截断为零长度。
  • mode:权限模式,用于指定共享内存对象的权限。这些权限位与创建文件时使用的权限位类似,但只考虑低 9 位。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询