std::thread 使用局部变量问题

std::thread 使用局部变量问题

std::thread 使C++能方便地使用线程,特别是使用Lambda表达式作为执行函数。但在使用Lambda表达式作为执行函数时或传递参数,却有一个很大的坑,就是局部变量作为参数。

示例:

 CProgressDlg prodlgTemp;
 SCallBackParam param;
 prodlgTemp.SetCallBackFunc(ExecuteCallBackProgress, (LPVOID)&param);
 prodlgTemp.DoModal();
LONG ExecuteCallBackProgress(LPVOID lpParam)
{
	//进度条对象指针
	SCallBackParam *pParam = reinterpret_cast<SCallBackParam*>(lpParam);
	CProgressDlg* pProgressDlg = (CProgressDlg *)pParam->m_lpParam2;
	SCallBackParam param;
	param.m_lpParam1 = (LPVOID)pProgressDlg;

	std::thread td([&param]()
	{
			int nType = CProgressDlg::EPTYPE_BEG;
		
			param.m_lpParam2 = (LPVOID)&nType;
			int nCount = 0;
			while (nCount < 100)
			{
				Sleep(50);
				nCount++;

				int nProgress = nCount;
				param.m_lpParam3 = (LPVOID)&nProgress;
				CProgressDlg::SetProgressFuncCallBack(&param);
			}
		}

	});

	return 0;
}

上述代码简单演示实现一个进度条功能,进度条窗口CProgressDlg,通过回调函数ExecuteCallBackProgress实现进度数值的显示。运行以上代码,程序会崩溃,提示abort错误。以上代码有两个问题:1)线程对象td没有调用detach()函数。thread::detach(): 从 thread 对象分离执行的线程,允许执行独立地持续。一旦线程退出,则释放所有分配的资源。调用detach后, *this 不再占有任何线程。上例代码,td对象消亡时,由于前面没有调用join()或者detach(),那它是joinable的,析构函数会调用terminate(),terminate()会调用abort(), abort()是非正常结束进程,不进行任何清理工作,直接终止程序。如果td不是joinable的,就不会引发terminate而非正常结束进程。2)用引用(或指针)传递局部变量参数。在线程分离的情况下,Lambda表达用引用捕获参数,当线程函数执行完后,会出现局部变量先被释放的情况,这时会引发内存指针无效的崩溃。所以在用Lambda表达式或函数参数时,一定要用值传递,并且要注意Lambda表达式不能有修改参数的目的。以上错误,如果没有这种意识是很难发现问题的,特别是问题2,明明主线程被窗口DoModal()阻塞了,线程执行函数还会出现窗口对象指针无效的错误,这种错误就会让人感觉莫名奇妙,也会花费大量的时间去调试。

正确的代码如下:

LONG ExecuteCallBackProgress(LPVOID lpParam)
{
	//进度条对象指针
	SCallBackParam *pParam = reinterpret_cast<SCallBackParam*>(lpParam);
	CProgressDlg* pProgressDlg = (CProgressDlg *)pParam->m_lpParam2;
	SCallBackParam param;
	param.m_lpParam1 = (LPVOID)pProgressDlg;

	std::thread td([param]mutable()
	{
			int nType = CProgressDlg::EPTYPE_BEG;
		
			param.m_lpParam2 = (LPVOID)&nType;
			int nCount = 0;
			while (nCount < 100)
			{
				Sleep(50);
				nCount++;

				int nProgress = nCount;
				param.m_lpParam3 = (LPVOID)&nProgress;
				CProgressDlg::SetProgressFuncCallBack(&param);
			}
		}

	});

    td.detach();
	return 0;
}

LONG ExecuteCallBackProgress(LPVOID lpParam)
{
	//进度条对象指针
	SCallBackParam *pParam = reinterpret_cast<SCallBackParam*>(lpParam);
	CProgressDlg* pProgressDlg = (CProgressDlg *)pParam->m_lpParam2;
	SCallBackParam param;
	param.m_lpParam1 = (LPVOID)pProgressDlg;

	std::thread td([](SCallBackParam param)
	{
		
			int nType = CProgressDlg::EPTYPE_BEG;
		
			param.m_lpParam2 = (LPVOID)&nType;
			int nCount = 0;
			while (nCount < 100)
			{
				Sleep(50);
				nCount++;

				int nProgress = nCount;
				param.m_lpParam3 = (LPVOID)&nProgress;
				CProgressDlg::SetProgressFuncCallBack(&param);
			}
		}
	
	},param);

	td.detach();
	return 0;
}

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值