题目有点大,其实主要讲述线程运行及退出时遇到的一些问题和解决办法以及注意事项。一个工业控制项目,用USB口采集数据,程序结构是主进程负责界面和算法,创建一个子线程负责USB通讯,读取数据,死循环。
参考MFC的线程演练编制,以下根据代码逐行说明:
1. 启动线程
用AfxBeginThread( cameraThrdPro, (LPVOID)this, THREAD_PRIORITY_TIME_CRITICAL )启动线程,这个方法的参数较多,这里只用前三个参数,第一个cameraThrdPro是线程处理函数,必须是一个静态或全局函数;第二个(LPVOID)this,把当前对象实例指针传到静态或全局函数中,通过它可以调用本实例的成员方法和数据;第三个THREAD_PRIORITY_TIME_CRITICAL把线程级别设到最高,以便实时采集和控制,避免卡顿现象。
2. 创建全局对象,控制线程结束
m_hEventKilled = CreateEvent(NULL, FALSE, FALSE, NULL); // auto reset, initially reset
3. 静态线程处理函数
UINT DynamicScan::cameraThrdPro(LPVOID pParam) // 线程处理函数,LPVOID pParam 指向本类
{
return ((DynamicScan *)pParam)->cameraThrd();
}
这个函数是一个过度函数,通过pParam转到类实例内部处理。
3. 实际线程处理
UINT DynamicScan::cameraThrd()
{
...... // 初始化
while( !m_bKill ) // 实时循环采集,主进程调用退出线程函数,设置m_bKill停止循环
{
int result = 0;
TRY
{
...... // 不耗时代码
if( !m_bKill ) // 所有耗时代码前加判断,如果已经结束,不再执行,避免线程长时间运行影响退出
{
...... // 耗时代码
}
// 数据读取完毕后不能在线程中修改界面(如SetWindowText等),应该发送消息的方法通知主进程显示新数据,
//用PostMessage发送消息,不能用SendMessage,因为在程序结束时主进程等待子线程结束,而SendMessage等待主进程返回,出现互相等待的情况而卡死
PostMessage( WM_COMMAND, TID_DS_DATA );
}
CATCH_ALL( e )
{
if( !e->m_bAutoDelete )
e->Delete();
Sleep( 1000 ); // 如果有错等1秒再读
}
END_CATCH_ALL
...... // 线程循环结束
SetEvent( m_hEventKilled ); // 置结束标识
return result;
}
4. 结束通讯线程
void DynamicScan::killThread()
{
// 设置线程结束标识
m_bKill = TRUE;
// 等待线程结束
#ifdef _DEBUG
WaitForSingleObject(m_hEventKilled, INFINITE); // DEBUG状态下长期等待,便于调试时发现问题
#else
WaitForSingleObject(m_hEventKilled, 500); // 发布状态等待500mm后强制结束,退出程序
#endif
}
参考资料:
MTRECALC 示例:支持多线程应用程序 https://msdn.microsoft.com/zh-cn/library/3kk6acaf(v=vs.90).aspx
VS环境中下拉菜单,帮助-》示例-》本地 Samples 文件夹。 MFC 高级示例 :MTRECALC 示例:支持多线程应用程序。
C:\Program Files (x86)\Microsoft Visual Studio 10.0\Samples\2052\VC2010SP1Samples.zip\C++\MFC\advanced\mtrecalc