boost::thread编程实战(3)——通过PostThreadMessage和PeekMessage实现线程通信

1. PostThreadMessage和PeekMessage的介绍
① PostMessage 和SendMessage 的区别
  • PostMessage 是异步的,SendMessage 是同步的。
  • PostMessage 只把消息放到队列,不管消息是不是被处理就返回,消息可能不被处理;
  • SendMessage等待消息被处理完了才返回,如果消息不被处理,发送消息的线程将一直处于阻塞状态,等待消息的返回。
    PostMessage 函数原型:
BOOL PostMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam);

hWnd:其窗口程序接收消息的窗口的句柄。可取有特定含义的两个值:HWND_BROADCAST:消息被寄送到系统的所有顶层窗口,包括无效或不可见的非自身拥有的窗口、 被覆盖的窗口和弹出式窗口。消息不被寄送到子窗口。NULL:此函数的操作和调用参数dwThread设置为当前线程的标识符PostThreadMessage函数一样

Msg:指定被寄送的消息。

wParam:指定附加的消息特定的信息。

lParam:指定附加的消息特定的信息。

返回值:如果函数调用成功,返回非零,否则函数调用返回值为零

参考链接:
windows下多线程通信方法
消息队列和GetMessage/PeekMessage、SendMessage/Postmesage的详解

② PostThreadMessage

PostThreadMessage方法可以将消息发送到指定线程。
函数原型:

BOOL PostThreadMessage(DWORD idThread,UINT Msg,WPARAM wParam, LPARAM lParam);

注意: PostThreadMessage参数除了ThreadId之外,基本和PostMessage相同。

③ PeekMessage 和GetMessage的区别
  • GetMessage是阻塞函数,它会在消息循环中会一直阻塞直到消息队列中出现了消息可以被获取;而PeekMessage是非阻塞函数,不管有没有获取到消息队列中的消息,它都会返回。
  • PeekMessage:有消息时返回TRUE,没有消息返回FALSE
  • GetMessage:有消息时且消息不为WM_QUIT时返回TRUE;如果有消息且为WM_QUIT则返回FALSE,没有消息时不返回
  • PeekMessage更多用来检测消息队里中是否有消息,它的最后一个参数可以用来指定获取到消息后要不要把消息从消息队列中移除。通常情况下通过PeekMessage检测到消息队列有消息之后,再调用GetMessage去获取。
  • PeekMessage函数原型:
BOOL PeekMessage(LPMSG IpMsg, HWND hWnd, UINT wMSGfilterMin, UINT wMsgFilterMax, UINT wRemoveMsg);

lpMsg:接收消息信息的MSG结构指针。
hWnd:其消息被检查的窗口句柄。
wMsgFilterMin:指定被检查的消息范围里的第一个消息。
wMsgFilterMax:指定被检查的消息范围里的最后一个消息。
wRemoveMsg:确定消息如何被处理。此参数可取下列值之一:

意义
PM_NOREMOVEPeekMessage处理后,消息不从队列里除掉。
PM_REMOVEPeekMessage处理后,消息从队列里除掉。
PM_NOYIELD此标志使系统不释放等待调用程序空闲的线程。可将PM_NOYIELD随意组合到PM_NOREMOVE或PM_REMOVE。

参考链接:
Windows消息传递机制详解
PeekMessage使用方法

2. 使用PostThreadMessage和PeekMessage实现线程间通信

程序思路:

  • 首先创建一个server线程,获取该线程的ID。
  • 接着创建一个client线程,将server线程的ID通过函数参数传递给client线程。
  • client线程主动向server线程发送自己的线程ID,之后再发送实际数据。
  • server线程循环接收消息,通过消息ID过滤得到client线程的消息。
  • server线程在收到client线程之后,发送接收的消息数给client线程。
  • 如果server线程收到WM_QUIT消息,表示client与其断开通信,自己也结束循环,不在接收消息。
#include <iostream>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <Windows.h>
#include <string.h>
#include <boost/lexical_cast.hpp>

using namespace boost;

DWORD getThreadId(boost::thread::id id){
	std::string threadId = boost::lexical_cast<std::string>(id);
	DWORD threadNumber = 0;
	sscanf(threadId.c_str(), "%lx", &threadNumber);
	return threadNumber;
}

void thread1(DWORD threadID){
	//向对方线程发送自己的线程id
	PostThreadMessage(threadID, WM_USER + 101, GetCurrentThreadId(), 0);
	Sleep(500);

	//发送自定义消息
	for (size_t i = 0; i < 4; i++)
	{
		std::cout << "Send:  " << i * 10 << " ,  " << i << std::endl;
		PostThreadMessage(threadID, WM_USER + 102, i * 10, i);
		Sleep(1000);
		
		MSG  msg;//在Windows程序中,消息是由MSG结构体来表示的。第二个成员变量message指定了消息的标识符
		DWORD id = 0;
		//PeekMessage函数,param1(lpMsg):接收消息信息的MSG结构指针;param4(wRemoveMsg):PM_REMOVE指PeekMessage处理后,消息从队列里除掉。
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			switch (msg.message)
			{
			case WM_USER + 201://WM_USER + 101是Fortrain发来的消息id
				std::cout << "Receive from " << threadID << ": "<< msg.wParam<< std::endl;
				break;
			default:
				break;
			}
		}
	}
	std::cout << "Send Quit" << std::endl;
	//发送关闭消息,WM_QUIT:关闭消息循环
	PostThreadMessage(threadID, WM_QUIT, 0, 0);
}

void thread2(int x){
	MSG msg;
	DWORD id = 0;
	int count = 0;
	bool flag = true;
	//发送自定义消息
	while (flag){
		//PeekMessage函数,param1(lpMsg):接收消息信息的MSG结构指针;param4(wRemoveMsg):PM_REMOVE指PeekMessage处理后,消息从队列里除掉。
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			switch (msg.message)
			{
			case WM_USER + 101://WM_USER + 101是Fortrain发来的消息id
				std::cout << "Receive threadID:" << msg.wParam << std::endl;
				id = msg.wParam;
				PostThreadMessage(id, WM_USER + 201, ++count, 0);
				break;
			case WM_USER + 102://WM_USER + 101是Fortrain发来的消息id
				std::cout << "Receive from " << id << ":" << msg.wParam << ", " << msg.lParam << std::endl;
				PostThreadMessage(id, WM_USER + 201, ++count, 0);
				break;
			case WM_QUIT:
				std::cout << "Receive from " << id << ": I quit, bye bye!" << std::endl;
				flag= false;
				break;
			default:
				break;
			}
		}
	}

}

int main(){
	boost::thread thrd2(boost::bind(&thread2, 2));
	DWORD id = getThreadId(thrd2.get_id());
	boost::thread thrd1(boost::bind(&thread1, id));
	thrd1.join();
	thrd2.join();

	return 0;
}

运行结果如下:
在这里插入图片描述

3. 使用PostThreadMessage和PeekMessage实现线程间字符串的传递

现在能实现线程间的通信了,值传递数值是不能满足自己的需求的。自己想要传递字符串,因此查阅了一些资料。
解决方法: 传送字符串地址(字符串得是CString类型,如果是string类型,需要使用c_str进行转化),可以将想要传送的数据强制转化为WPARAMLPARAM类型。

程序实例:

#include <iostream>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <Windows.h>
#include <string.h>
#include <boost/lexical_cast.hpp>
using namespace boost;

DWORD getThreadId(boost::thread::id id){
	std::string threadId = boost::lexical_cast<std::string>(id);
	DWORD threadNumber = 0;
	//threadNumber = std::stoul(threadId, nullptr, 16);
	sscanf(threadId.c_str(), "%lx", &threadNumber);
	return threadNumber;
}

void thread1(DWORD threadID){
	//向对方线程发送自己的线程id
	PostThreadMessage(threadID, WM_USER + 101, GetCurrentThreadId(), 0);
	Sleep(500);

	//发送自定义消息
	for (size_t i = 0; i < 4; i++)
	{
		 std::string str = "hello, send message to you";
		std::cout << "Send:  " << str << std::endl;
		PostThreadMessage(threadID, WM_USER + 102, (WPARAM)str.length(), (LPARAM)str.c_str());

		Sleep(1000);
		MSG  msg;//在Windows程序中,消息是由MSG结构体来表示的。第二个成员变量message指定了消息的标识符
		DWORD id = 0;
		//PeekMessage函数,param1(lpMsg):接收消息信息的MSG结构指针;param4(wRemoveMsg):PM_REMOVE指PeekMessage处理后,消息从队列里除掉。
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			switch (msg.message)
			{
			case WM_USER + 201://WM_USER + 101是Fortrain发来的消息id
				std::cout << "Receive from " << threadID << ": "<< msg.wParam<< std::endl;
				break;
			default:
				break;
			}
		}
	}
	std::cout << "Send Quit" << std::endl;
	//发送关闭消息,WM_QUIT:关闭消息循环
	PostThreadMessage(threadID, WM_QUIT, 0, 0);
}

void thread2(int x){
	MSG msg;
	DWORD id = 0;
	int count = 0;
	bool flag = true;
	//发送自定义消息
	while (flag){
		//PeekMessage函数,param1(lpMsg):接收消息信息的MSG结构指针;param4(wRemoveMsg):PM_REMOVE指PeekMessage处理后,消息从队列里除掉。
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			switch (msg.message)
			{
			case WM_USER + 101://WM_USER + 101是Fortrain发来的消息id
				std::cout << "Receive threadID:" << msg.wParam << std::endl;
				id = msg.wParam;
				PostThreadMessage(id, WM_USER + 201, ++count, 0);
				break;
			case WM_USER + 102://WM_USER + 101是Fortrain发来的消息id
				std::cout << "Receive from " << id << ":" << (int)msg.wParam << ", " << (const char*)msg.lParam << std::endl;
				PostThreadMessage(id, WM_USER + 201, ++count, 0);
				break;
			case WM_QUIT:
				std::cout << "Receive from " << id << ": I quit, bye bye!" << std::endl;
				flag= false;
				break;
			default:
				break;
			}
		}
	}

}

int main(){
	boost::thread thrd2(boost::bind(&thread2, 2));
	DWORD id = getThreadId(thrd2.get_id());
	boost::thread thrd1(boost::bind(&thread1, id));
	thrd1.join();
	thrd2.join();
	return 0;
}

程序运行结果:
在这里插入图片描述

参考链接:
SendMessage和PostMessage发送消息(不同进程传递字符串)
PostMessage 怎么传递 CString 类型的字符串?
PostMessage传递 CString 类型的字符串
将字符串作为PostMessage参数传递的问题?

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用\[1\]:在MFC环境下实现线程串口通信,需要涉及线程创建及控制、串口同步异步操作、内存非法访问(或者说是线程同步)、线通信、Windows消息响应过程等。\[1\]在多线程访问冲突方面,可能会遇到一个问题,即主线程和IO线程同时使用同一个串口通信缓冲区,导致非法访问。解决方法可以是将所有的串口IO通信交给子线程来处理,主线程通过发送消息给子线程来实现通信,可以使用API函数PostThreadMessage来发送消息给子线程,其中第一个参数是子线程的ID。\[2\]在MFC中,可以使用AfxBeginThread函数来创建新的线程,该函数返回线程的指针。在创建线程时,需要指定线程函数地址、线程参数、线程优先级等参数。\[3\] 问题: 如何在MFC中实现串口通信的多线程? 回答: 在MFC中实现串口通信的多线程,可以按照以下步骤进行操作。首先,需要创建一个新的线程来处理串口通信。可以使用AfxBeginThread函数来创建线程,该函数需要指定线程函数地址、线程参数、线程优先级等参数。在线程函数中,可以调用相应的串口通信函数来进行数据的发送和接收。为了避免多线程访问冲突,可以将所有的串口IO通信交给子线程来处理,主线程通过发送消息给子线程来实现通信。可以使用API函数PostThreadMessage来发送消息给子线程,其中第一个参数是子线程的ID。通过这种方式,可以实现线程和子线程之间的数据交互和同步操作。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* *2* [多线程串口通信 MFC CSerialPort](https://blog.csdn.net/denggou1893/article/details/101238521)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [c++学习 | MFC —— 串口通信(二)创建线程](https://blog.csdn.net/florence_jz/article/details/125913281)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值