C++多进程通信、信号量、内存共享

概述

说明:本文所述方法基于windows操作系统实现多进程通信,实现进程间同步、传递图像数据。
知识点:C++、信号量、共享内存、多进程。

进程间通信

管道(Pipe):管道可用于具有亲缘关系进程间的通信,允许一个进程和另一个与它有共同祖先的进程之间进行通信。
命名管道(named pipe):命名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信。命名管道在文件系统中有对应的文件名。命名管道通过命令mkfifo或系统调用mkfifo来创建。
信号(Signal):信号是比较复杂的通信方式,用于通知接受进程有某种事件发生,除了用于进程间通信外,进程还可以发送信号给进程本身;Linux除了支持Unix早期信号语义函数sigal外,还支持语义符合Posix.1标准的信号函数sigaction(实际上,该函数是基于BSD的,BSD为了实现可靠信号机制,又能够统一对外接口,用sigaction函数重新实现了signal函数)。
消息(Message)队列:消息队列是消息的链接表,包括Posix消息队列system V消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺
共享内存:使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。是针对其他通信机制运行效率较低而设计的。往往与其它通信机制,如信号量结合使用,来达到进程间的同步及互斥。
信号量(semaphore):主要作为进程间以及同一进程不同线程之间的同步手段。

代码实现

使用C++实现两个进程之间通信:

1:使用共享内存实现两个进程之间传递数据
2:使用信号量实现两个进程同步
共享内存传递int、vector、图像
思路:父进程将需要发送的数据拷贝到申请的共享内存中,子进程从共享内存中把数据拷贝到本地。
注意:函数memcpy(lpBase, &arr[0], 8);在执行时,参数定义如下:
1:目标地址
2:源起始地址
3:拷贝的字节数
因此在传递vector变量时我们需要传入的第二个变量是&arr[0],因为这才是动态数组的起始地址,而&arr是vector对象的地址,并不是数组的起始地址
拷贝的字节数,因为int占4个字节,因此我们把从&arr[0]开始的8个字节的内容复制到共享内存中。
在传递图像数据时,我这里采取的方法是,父进程对图像编码,存入共享内存,子进程读出数据后解码。
子进程在接收数据时,需要提前申请空间
vector arr(2);
std::vector jpg_buff(15676);
BUF_SIZE, 为文件大小,所传递的数据量不能大于BUF_SIZE。

父进程

// 定义共享数据
         //联合Opencv传递图像数据
	cv::Mat std;
	cv::Mat hel;
	std = cv::imread("hello.jpg");
	cv::Mat dst_mat = std(cv::Rect(0, 0, 250, 250));
	std::vector<uchar> jpg_buff;
	bool ret = cv::imencode(".jpg", dst_mat, jpg_buff);
         //传递整形数据
         int a;
         //传递数组
         vector<int>arr;
         arr.pushback(211);
         arr.pushback(311);
	///*hel=cv::imdecode(jpg_buff,0);
	//cv::imwrite("000.jpg", hel);*/


// 创建共享文件句柄 
	HANDLE hMapFile = CreateFileMapping(
		INVALID_HANDLE_VALUE,   // 物理文件句柄
		NULL,   // 默认安全级别
		PAGE_READWRITE,   // 可读可写
		0,   // 高位文件大小
		BUF_SIZE,   // 定义文件大小
		L"Sharememory"   // 共享内存名称
	);
	
// 映射缓存区视图 , 得到指向共享内存的指针
	LPVOID lpBase = MapViewOfFile(
		hMapFile,            // 共享内存的句柄
		FILE_MAP_ALL_ACCESS, // 可读写许可
		0,
		0,
		BUF_SIZE//定义文件大小
	);

// 将数据拷贝到共享内存
	//传递整形数据
	memcpy(lpBase, &a, 4);
        
        //传递数组
        memcpy(lpBase, &arr[0], 8);
        //传递图片
        memcpy(lpBase, &jpg_buff[0], 15676);
	
 线程挂起等其他线程读取数据
	Sleep(15000);

 解除文件映射
	UnmapViewOfFile(lpBase);
 关闭内存映射文件对象句柄
	CloseHandle(hMapFile);

子进程:

// 打开共享的文件对象
	HANDLE hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, NULL, L"Sharememory");
//申请变量准备接收数据
	vector<int> arr(2);
	int a = 0;
	std::vector<uchar> jpg_buff(15676);
 
	if (hMapFile) {
     
		LPVOID lpBase= MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
		cv::Mat hel;
                //以下三种数据和父进程发送的数据要一一对应
		memcpy(&jpg_buff[0], lpBase, 15676);
		memcpy(&a, lpBase, 4);
                memcpy(&arr[0], lpBase, 4);
                
                //图像解码
		hel = cv::imdecode(jpg_buff, 0);
		cv::imwrite("009.jpg", hel);
  
		// 解除文件映射
		UnmapViewOfFile(lpBase);
		// 关闭内存映射文件对象句柄
		CloseHandle(hMapFile);
	}
	else {
		// 打开共享内存句柄失败
		cout << "打开共享失败!" << endl;
}

信号量实现进程同步

信号量通信较为简单,使用时应注意以下几点:
1:ReleaseSemaphore(myHSemaphore, 1, NULL);相当于发送一次消息
2:WaitForSingleObject(myHSemaphore, INFINITE);相当于消耗一次消息

父进程:

//信号量
	HANDLE myHSemaphore;
	
	myHSemaphore = CreateSemaphore(NULL, FALSE, TRUE, TEXT("TOCHILD"));
	if (myHSemaphore == NULL)
	{
		
		AfxMessageBox(TEXT("ERROR"));
		return;
	}
	Sleep(5000);
	ReleaseSemaphore(myHSemaphore, 1, NULL);
	
	Sleep(2000);
	WaitForSingleObject(myHSemaphore, INFINITE);
	
	CloseHandle(myHSemaphore);
	
	AfxMessageBox(TEXT("OK"));

子进程:

   HANDLE myHSemaphore;
    myHSemaphore = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, TEXT("TOCHILD"));
	if (myHSemaphore == NULL)
	{
		return FALSE;
	}
	std::cout << "waiting " << std::endl;

	WaitForSingleObject(myHSemaphore, INFINITE);

	std::cout << "had waited " << std::endl;

	ReleaseSemaphore(myHSemaphore, 1, NULL);
	Sleep(500);
	CloseHandle(myHSemaphore);

	return TRUE;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值