进程之间通信的几种方式,总有一款适合你
进程之间通信的几种方式
前言
这个问题面试官必问的好吧,这是非常经典的问题,正好之前的项目中有这样的经历,所以就咱们的项目出发,讲一下进程之间通信的几种方式。
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操作)
上一篇: java并发原理实战(14)--自己实现简易web服务器
下一篇: 死锁及其解决
推荐阅读