进程之间通信的几种方式,总有一款适合你

进程之间通信的几种方式

  • 前言
  • shared memory
  • PipeMsg
  • MsgQueue

前言

这个问题面试官必问的好吧,这是非常经典的问题,正好之前的项目中有这样的经历,所以就咱们的项目出发,讲一下进程之间通信的几种方式。

shared memory

共享内存,大家读写双方约定一块内存地址,然后咱们分别读写这块地址的数据(当然,大家也要一起约定好数据的格式)。记得加锁哦。
咱们看一下shared memory的写和读是咋搞的:

    //1.没有锁的话,创建锁,然后尝试获取锁
    HANDLE Gmutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, TEXT("MutexForSharedMemory"));
    if (Gmutex == NULL)
    {
        Gmutex = CreateMutex(NULL, FALSE, TEXT("MutexForSharedMemory"));
    }

    WaitForSingleObject(Gmutex, INFINITE);  //等待获取Gmutex,不然就一直卡死在这里,时间是infinite

    //创建共享内存区域
    SECURITY_ATTRIBUTES ScrtyAttr = { 0 };
    ScrtyAttr.bInheritHandle = FALSE;
    ScrtyAttr.lpSecurityDescriptor = NULL;
    ScrtyAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
    HANDLE GSharedMem = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, TEXT("Global\\SharedMem"));
    if (GSharedMem == NULL)
    {
        cout << "共享内存创建失败!" << endl;
        //return 0;
    }
    //得到共享内存地址指针
    PVOID pSharedMem = MapViewOfFile(GSharedMem, FILE_MAP_ALL_ACCESS, 0, 0, 4096);
    if (pSharedMem == NULL)
    {
        cout << "内存指针映射失败!" << endl;
        return 0;
    }
    //创建待写入共享内存数据
    struct FrameDetails data;
    data.dataa = 1;
    data.datab = 2;
    data.datac = 3;
    data.datad = 4;
    memcpy(pSharedMem, &data, sizeof(data));
    cout << "完成数据写入!" << endl;
    //解除映射
    UnmapViewOfFile(pSharedMem);
    //关闭句柄
    CloseHandle(GSharedMem);
    for (int i = 0; i < 10; ++i)
    {
        cout << "测试打印:" << i << endl;
        Sleep(1000);
    }
    ReleaseMutex(Gmutex);
    cout << "释放锁!" << endl;

咱们再看看读是咋搞的:

    //打开共享内存
    HANDLE GSharedMem = OpenFileMapping(FILE_MAP_READ, false, TEXT("Global\\SharedMem"));
    if (GSharedMem == NULL)
    {
        cout << "打开共享内存失败!" << endl;
        //return 0;
    }
    //得到共享内存地址指针
    PVOID pSharedMem = MapViewOfFile(GSharedMem, FILE_MAP_READ, 0, 0, 4096);
    if (pSharedMem == NULL)
    {
        cout << "内存指针映射失败!" << endl;
        //return 0;
    }
    //输出结果
    struct FrameDetails data = {0};
    memcpy(pSharedMem, &data, sizeof(data));
    //cout << "数据读取成功!" << data.dataa << data.datab << data.datac << data.datad << endl;
    for (int i = 0; i < 10; ++i)
    {
        cout << "测试打印:" << i << endl;
    }
    //解除映射
    UnmapViewOfFile(pSharedMem);
    //关闭句柄
    CloseHandle(GSharedMem);
    ReleaseMutex(Gmutex);
    cout << "释放锁!" << endl;

还是很简单的对吧。

PipeMsg

管道通信其实也非常好理解。当然我们这里是进程和进程间的通信,所以是命名管道而不是匿名管道。
管道通信可以做到有来有回。
先看看如何创建一个命名管道:

HANDLE WINAPI CreateNamedPipe(
  __in          LPCTSTR lpName,       //管道名称
  __in          DWORD dwOpenMode,  //管道访问方式
  __in          DWORD dwPipeMode,   //管道模式
  __in          DWORD nMaxInstances,
  __in          DWORD nOutBufferSize,
  __in          DWORD nInBufferSize,
  __in          DWORD nDefaultTimeOut,
  __in          LPSECURITY_ATTRIBUTES lpSecurityAttributes
);

这就是创建一个命名管道然后返回一个句柄。
那么等待客户端连接管道呢?

        BOOL WINAPI ConnectNamedPipe(
            HANDLE hNamedPipe,//命名管道句柄
            LPOVERLAPPED lpOverlapped//一般为NULL
        );

咱们可以在创建管道的时候设置等待时间参数(我设置成无穷大)。
那么客户端如何连接这个管道呢?

        BOOL WINAPI ConnectNamedPipe(
            HANDLE hNamedPipe,//命名管道句柄
            LPOVERLAPPED lpOverlapped//一般为NULL
        );

管道双方建立通信后,打开管道进行数据通信,使用CreateFile,ReadFile和WriteFile进行数据的读写。
当然,记得使用的时候加锁,别让大家一块用。
那如何搞同步呢?A把信息发给B,B虽然确实收到了,可是A不知道啊!咋办?
很简单,windows event了解一下。
进程之间通信的几种方式,总有一款适合你_第1张图片
看吧,用setevent和waitevent就搞定了。

MsgQueue

建议了解一下MSMQ,这个东西非常好用。(我说的可不是你理解的那种windows form传消息)
delphi使用连接
C++使用链接
对了,记住,get方法和peek方法的不同,peek只是读取,但是不移除消息(这才是正儿八经的queue操作)

你可能感兴趣的:(实现自己的OS)