欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-03-08 18:58:34
...

进程之间通信的几种方式

前言

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

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了解一下。
进程之间通信的几种方式,总有一款适合你
看吧,用setevent和waitevent就搞定了。

MsgQueue

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