MFC多线程学习笔记三:线程间的通信

使用全局变量进行通信

对于标准型的全局变量,建议使用volatile修饰符,告诉编译器无需优化(不放入寄存器),该值可以被外部改变。

如果线程间需要传递的信息比较复杂,可以使用结构,通过传递指向结构的指针来传递信息。

volatile修饰符

  1. 防止编译器优化

    声明为volatile的变量不会被编译器优化,每次访问都会直接读取内存值,避免因优化导致的数据不一致问题。 ‌12

  2. 保证内存可见性

    在多线程环境中,volatile变量的修改会立即同步到主内存,其他线程能读取到最新值,解决线程间数据不一致问题。 ‌34

  3. 禁止指令重排序

    通过插入内存屏障,防止编译器或处理器对volatile变量相关指令进行重排序,确保程序执行顺序符合预期。

https://blog.csdn.net/hd51cc/article/details/155131444?sharetype=blogdetail&sharerId=155131444&sharerefer=PC&sharesource=hd51cc&spm=1011.2480.3001.8118

如链接示例中

cpp 复制代码
volatile bool bExit1 = false;
volatile bool bExit2 = false;

...


void CMFCApplDlg::OnPriorityThread1()
{
	int prior;
	//线程存在
	if (m_pThread1 && !bExit1)
	{
		prior = m_pThread1->GetThreadPriority();
		if (prior == THREAD_PRIORITY_NORMAL )
		{
			m_pThread1->SetThreadPriority(THREAD_PRIORITY_ABOVE_NORMAL);
			AfxMessageBox(L"线程1的优先级提升1级", MB_OK);
		}
		else
		{
			m_pThread1->SetThreadPriority(THREAD_PRIORITY_NORMAL);
			AfxMessageBox(L"线程1的优先级降低1级", MB_OK);
		}
	}
}


void CMFCApplDlg::OnPriorityThread2()
{
	int prior;
	//线程存在
	if (m_pThread2 && !bExit2)
	{
		prior = m_pThread2->GetThreadPriority();
		if (prior == THREAD_PRIORITY_NORMAL)
		{
			m_pThread2->SetThreadPriority(THREAD_PRIORITY_ABOVE_NORMAL);
			AfxMessageBox(L"线程2的优先级提升1级", MB_OK);
		}
		else
		{
			m_pThread2->SetThreadPriority(THREAD_PRIORITY_NORMAL);
			AfxMessageBox(L"线程2的优先级降低1级", MB_OK);
		}
	}
}

....



void CMFCApplDlg::OnStopThread1()
{
	bExit1 = true;
	m_bEnable1 = true;
}


void CMFCApplDlg::OnStopThread2()
{
	bExit2 = true;
	m_bEnable2 = true;
}

使用自定义消息进行通信

步骤

1)定义一个自定义消息。

在头文件中自定义消息、声明消息处理函数。

在CPP文件中,映射消息,定义消息处理函数。

2)在一个函数中调用::PostMessage()向另一个线程发送自定义消息


PostMessageA 函数

cpp 复制代码
BOOL PostMessageA(
  [in, optional] HWND   hWnd,
  [in]           UINT   Msg,
  [in]           WPARAM wParam,
  [in]           LPARAM lParam
);

hWnd:窗口过程的句柄是接收消息。 以下值具有特殊含义。

价值 意义
HWND_BROADCAST ((HWND)0xffff) 该消息将发布到系统中的所有顶级窗口,包括已禁用或不可见的未所有者窗口、重叠的窗口和弹出窗口。 消息不会发布到子窗口。
该函数的行为类似于调用 PostThreadMessagedwThreadId 参数设置为当前线程的标识符。

Msg:要发布的消息。

wParam:其他特定于消息的信息。

lParam:其他特定于消息的信息。

返回值:如果函数成功,则返回值为非零。如果函数失败,则返回值为零。


范例

cpp 复制代码
UINT CalcPrime(LPVOID param);
cpp 复制代码
int n = 0;

UINT CalcPrime(LPVOID param)
{
	n = 0;
	long j, k;
	for (long i = 1; i <= 100000000; i += 2)
	{
		k = (long)sqrt(i);
		for (j = 2; j <= k; j++)
		{
			if (i % j == 0)
			{
				break;
			}
		}
		if (j >= k + 1)
		{
			n += 1;
		}
	}

	return 0;
}

程序优化

cpp 复制代码
const int WM_CALCULATE = WM_USER + 100;//自定义消息
...
afx_msg LONG OnThreadEnd(WPARAM aParam, LPARAM lParam);//消息处理函数

cpp 复制代码
BEGIN_MESSAGE_MAP(CMFCDlg, CDialogEx)
    ...
	ON_MESSAGE(WM_CALCULATE, OnThreadEnd)//自定义消息映射
END_MESSAGE_MAP()

LONG CMFCDlg::OnThreadEnd(WPARAM aParam, LPARAM lParam)
{
	CString s;
    s.Format(L"当前个数:%d .", n);
    AfxMessageBox(s);
	return 0;
}

void CMFCDlg::OnBnClickedPrime()
{
	HWND hWnd = GetSafeHwnd();//获取窗口句柄
	AfxBeginThread(CalcPrime, hWnd);

}



UINT CalcPrime(LPVOID param)
{
	n = 0;
	long j, k;
	for (long i = 1; i <= 10000000; i += 2)
	{
		k = (long)sqrt(i);
		for (j = 2; j <= k; j++)
		{
			if (i % j == 0)
			{
				break;
			}
		}
		if (j >= k + 1)
		{
			n += 1;
		}
	}
	::PostMessage((HWND)param, WM_CALCULATE, n, 0);//向主线程发送消息WM_CALCULATE
	return 0;
}

当计算结束,自动弹出对话框。这才是想要的结果

相关推荐
2301_764441337 小时前
Aella Science Dataset Explorer 部署教程笔记
笔记·python·全文检索
Bathwind-w7 小时前
FOC开发工具学习
学习
Coder_Boy_7 小时前
DDD从0到企业级:迭代式学习 (共17章)之 四
java·人工智能·驱动开发·学习
派大鑫wink8 小时前
【Java 学习日记】开篇:以日记为舟,渡 Java 进阶之海
java·笔记·程序人生·学习方法
deng-c-f8 小时前
Linux C/C++ 学习日记(49):线程池
c++·学习·线程池
HyperAI超神经8 小时前
【vLLM 学习】Prithvi Geospatial Mae
人工智能·python·深度学习·学习·大语言模型·gpu·vllm
永远都不秃头的程序员(互关)9 小时前
大模型Agent落地实战:从核心原理到工业级任务规划器开发
笔记
TL滕10 小时前
从0开始学算法——第十八天(分治算法)
笔记·学习·算法
算法与双吉汉堡10 小时前
【短链接项目笔记】Day2 用户注册
java·redis·笔记·后端·spring
思成不止于此10 小时前
【MySQL 零基础入门】MySQL 约束精讲(一):基础约束篇
数据库·笔记·sql·学习·mysql