进程同步通信
Proc
#include <semaphore.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
int semctl(int sem_id, int sem_num, int command, ...);
int semget(key_t key, int num_sems, int sem_flags);
int semop(int sem_id, struct sembuf *sem_ops, size_t num_sem_ops);
// linux 共享内存+信号量 https://blog.csdn.net/fengweibo112/article/details/119611439
// semget https://www.cnblogs.com/52php/p/5851570.html
class Monitor
{
public:
Monitor(std::string path1, std::string path2);
~Monitor();
public:
void enq();
void ouq();
void fun();
public:
int keySem;
int keyShm;
int semNum;
void* shm;
};
Monitor(std::string path1, std::string path2)
{
keySem = ftok(path1.c_str(), 1);
keyShm = ftok(path2.c_str(), 2);
semId = semget(keySem, 0, 0);
shmId = shmget(keyShm, 0, 0);
if (-1 == semId)
{
semId = semget(keySem, semNum, IPC_CREAT | IPC_EXCL | 0666)
}
if (-1 == shmId)
{
semId = shmget(keySem, Size, ?);
}
}
但是这种方法虽然没有明说被遗弃,但是很多人已经默认过时不再使用 // <sys/sem.h>
当前更多使用的是<semaphore.h>
简单说一下各个函数
-
ftok(pahtname, num)
根据
pathname
和num
来生成一个key
,用于semget\shmget\mesget
-
semget()
获取信号量
-
shmget()
获取共享内存
-
mesget()
获取消息
管程、进程间通信(管道,共享内存,消息)
管程
首先明白,管程需要自己写,本质是将pv操作和共享内存进行了封装(java
和Golang
好像有现成的包)
管程封装成为一种结构或者软件包?
-
必要性
- 不进行封装的情况下,pv操作和共享内存独立,操作的时候经常会出现匹配问题
-
模型
管程分为两种模型
MESA
模型HOARE
模型
-
不得不使用管程
Sure. Suppose you want to take an action if you can acquire the lock, but if some other object already owns it, you don’t want to block for longer than a certain time:
bool gotMonitor = false; try { Monitor.TryEnter(monitor, 500, ref gotMonitor); if (gotMonitor) { // Okay, we're in the lock. We can do something useful now. } else { // Timed out - do something else } } finally { if (gotMonitor) { Monitor.Exit(monitor); } }
大佬说:
-
管程不是一个独立的程序,而是一个概念,像
golang
中的wait_group
和java
中的synchronized
都是,但是 c++好像没有类似的库,但是可以带着mutex
和condition_variable
自己实现类似管程的功能 -
管程不算是一个独立的程序,而相当于一个
Model
,不应该说有一个管程,而应该是使用管程Monitor
-
可以理解为,假设
C++
有这么一个类库,不同的程序使用这一个相同的Minitor
类来操作互斥资源
-
命名管道(FIFO)
与管道的区别:提供了一个路径名与之关联,以
FIFO
文件的形式存储于文件系统中,能够实现任何两个进程之间通信。 而匿名管道对于文件系统是不可见的,它仅限于在父子进程之间的通信
#pragma once
#include "stdafx.h"
#include <windows.h>
#define BUF_SIZE 4096
class Monitor
{
public:
Monitor();
~Monitor();
void PV(int flag);
public:
HANDLE hMapFile; // 新创建的文件映射对象的句柄
LPVOID lpBase; // 内存映射视图
HANDLE hmutex; // 互斥锁
char szBuffer[100];
};
#include "Monitor.h"
Monitor::Monitor()
{
hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, NULL, L"ShareMemory");
if (!hMapFile)
{
hMapFile = CreateFileMapping(
INVALID_HANDLE_VALUE, // 物理文件句柄
NULL, // 默认安全级别
PAGE_READWRITE, // 可读可写
0, // 高位文件大小
BUF_SIZE, // 地位文件大小
L"ShareMemory" // 共享内存名称
);
}
lpBase = MapViewOfFile(
hMapFile, // 共享内存的句柄
FILE_MAP_ALL_ACCESS, // 可读写许可
0,
0,
BUF_SIZE
);
hmutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, TEXT("MutexTest"));
if (hmutex == NULL)
{
hmutex = CreateMutex(NULL, false, TEXT("MutexTest"));
}
}
Monitor::~Monitor()
{
if (hmutex != NULL)
{
CloseHandle(hmutex);
}
UnmapViewOfFile(lpBase);
CloseHandle(hMapFile);
}
void Monitor::PV(int flag)
{
WaitForSingleObject(hmutex, INFINITE);
if (flag == 1)
strcpy((char*)lpBase, szBuffer);
else if (flag == 2)
strcpy(szBuffer, (char*)lpBase);
ReleaseMutex(hmutex);
}
共享内存
命名管道中的示例,使用的就是共享内存,不再重复代码
Linux
中的共享内存是shmget
那一系列,在windows
下无法使用,所以先不考虑,想用的时候可以直接搜,教程不少
消息
Linux
中用的是mesget
,windows
下无法使用,可以自己搜一下
示例代码中用到的函数
#include <sys/shm.h>
共享内存
-
LPVOID lpBase;
// 内存映射视图 -
hMapFile = CreateFileMapping();
// 创建共享内存 -
lpBase = MapViewOfFile();
// 共享内存映射 -
使用
strcpy(szBuffer, (char*)lpBase);
strcpy((char*)lpBase, szBuffer);
-
释放
UnmapViewOfFile(lpBase);
CloseHandle(hMapFile);
mutex
-
HANDLE hmutex;
// 互斥锁 -
创建
hmutex = CreateMutex(NULL, false, TEXT("MutexTest"));
-
打开
hmutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, TEXT("MutexTest"));
-
关闭
ReleaseMutex(hmutex);