Linux进程间通信之共享内存

在Linux上可以使用共享内存进行进程间通信,他的主要特点如下:

  1. 适用于非父子进程间通信。
  2. 通信的效率很高,特别是数据量比较大的时候。

示例代码如下:

/**
 * @file ProcessSharedMemory.cpp
 * @author DennisMi (https://www.dennisthink.com/)
 * @brief Linux使用共享内存进行通信
 * @version 0.1
 * @date 2020-06-01
 * 
 * @copyright Copyright (c) 2020
 * 
 */
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/sem.h>

#include <errno.h>
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <string>
#include <string.h>
#include <sys/shm.h>


const int G_SEMAPHORE_KEY=1990;
const int G_SHARED_MEM_KEY=1024;

struct SharedMem_St 
{
    pid_t m_pid;
    char  m_msg[128];
};

union semun
{
	int val;
	struct semid_ds *buf;
	unsigned short *arry;
};


void Semaphore_P(const int semaId)
{
    struct sembuf sem_b;
	sem_b.sem_num = 0;
	sem_b.sem_op = -1;//P()
	sem_b.sem_flg = SEM_UNDO;
	if(semop(semaId, &sem_b, 1) == -1)
	{
		std::cerr<<"semaphore_p failed"<<std::endl;
		return ;
	}
    
	return;
}

void Semaphore_V(const int semaId)
{
    struct sembuf sem_b;
	sem_b.sem_num = 0;
	sem_b.sem_op = 1;//V()
	sem_b.sem_flg = SEM_UNDO;
	if(semop(semaId, &sem_b, 1) == -1)
	{
		std::cerr<< "semaphore_v failed"<<std::endl;
		return ;
	}
}

void WriteSharedMem(SharedMem_St* pMem)
{
    pMem->m_pid = getpid();
    memset(pMem->m_msg,0,128);
    std::string strTime = std::to_string(time(NULL));
    strcpy(pMem->m_msg,strTime.c_str());
    std::cout<<"Process Write SharedMem: "<<getpid()<<" "<<strTime<<std::flush<<std::endl;
}

void ReadSharedMem(SharedMem_St* pMem)
{
    std::cout<<"Process Id: "<<getpid()<<"  Read: "<<pMem->m_pid<<"  "<<pMem->m_msg<<std::flush<<std::endl;
}

using CallBackFunc = decltype(ReadSharedMem);

int SharedMemProcess(CallBackFunc& pCallBack)
{
    std::cout<<"Process Id: "<<getpid()<<" is running"<<std::endl;
    int semaId = semget(G_SEMAPHORE_KEY,1,IPC_CREAT|0666);
    if(semaId < 0)
    {
        std::cerr<<" create semaphore failed"<<std::endl;
        return -1;
    }
    SharedMem_St * pMem = nullptr;
    int sharedMemId = shmget(G_SHARED_MEM_KEY,sizeof(SharedMem_St),0666|IPC_CREAT);
    if(sharedMemId < 0)
    {
        if(EEXIST == errno)
        {
            sharedMemId = shmget(G_SEMAPHORE_KEY,sizeof(SharedMem_St),0666);
            pMem = (SharedMem_St*)shmat(sharedMemId,NULL,0);
            std::cout<<pMem->m_pid<<std::endl;
        }
    }
    else
    {
        pMem = (SharedMem_St*)shmat(sharedMemId,NULL,0);
        std::cout<<pMem->m_pid<<std::endl;
    }
   
    

    if(pMem)
    {
        memset(pMem,sizeof(SharedMem_St),0);
        for(int i = 0 ; i < 5; i++)
        {
            Semaphore_V(semaId);
            pCallBack(pMem);
            Semaphore_P(semaId);
            sleep(rand()%10);
        }
    }
    union semun sem_union;
    if(semctl(semaId,0,IPC_RMID,sem_union) == -1)
    {
        std::cout<<"Process Id: "<<getpid()<<" remove semaphore failed"<<std::endl;
    }
    return 0;
}


int main(int argc, char *argv[])
{
    pid_t fid= fork();
    if(fid < 0)
    {
        return 0;
    }
    
    if(fid == 0)
    {
        SharedMemProcess(WriteSharedMem);
    }
    else
    {
        SharedMemProcess(ReadSharedMem);
    }
    return 0;
}

示例效果演示: