MFC重现"User Breakpoint called from code at"错误——CString在多线程中容易导致的问题

一重现该错误

由于最近在一个项目中总是会莫名其妙的出现"User Breakpoint called from code at"错误,该错误不是每次运行的时候都出现,而是是不是会出现(Debug下),有时候10分钟,有时候则几个小时。这到底是由什么引起的呢?

由于每次运行的时候,都是与CString类相关,而且又是在多线程编程模式下,于是,就想复制该情况,重现该错误。我是这么做的。

VC6基于对话框模式新建一个工程,在CCTestMutiThreadDlg的cpp文件中所有函数外部创建一个CString类全局变量和三个操作该变量的线程函数。

CString g_str;
UINT Proc1(LPVOID param)
{
	while(1)
		g_str = "FisrtThread";
	
	return 0;
}
UINT Proc2(LPVOID param)
{
	while(1)
		g_str = "SecondThread";
	return 0;
}
UINT Proc3(LPVOID param)
{
	while(1)
		g_str = "ThirdThread";
	return 0;
}

给对话框增加一个按钮,在按钮的响应函数中添加以下代码

	AfxBeginThread(Proc1,this);
	AfxBeginThread(Proc2,this);
	AfxBeginThread(Proc3,this);
	Sleep(100000);

之后运行程序,点击对话框按钮,就可以看到弹出上述错误信息了!

二修复错误

上述错误是由于多线程访问一全局CString时,由于CString不是线程安全对象,所以导致出现错误。怎样改呢?很显然,要对线程进行同步处理。这里我们用临界区的方法进行同步。

首先在CCTestMutiThreadDlg的cpp文件中定义一个全局临界区对象CRITICAL_SECTION g_cs;

然后在按钮响应函数中线程开始之前,对临界区进行初始化和最后的删除

	InitializeCriticalSection(&g_cs);
	AfxBeginThread(Proc1,this);
	AfxBeginThread(Proc2,this);
	AfxBeginThread(Proc3,this);
	InitializeCriticalSection(&g_cs);
 	Sleep(100000);
	DeleteCriticalSection(&g_cs);
最后是同步各个线程

UINT Proc1(LPVOID param)
{
	while(1)
	{
		EnterCriticalSection(&g_cs);
		g_str = "FisrtThread";
		LeaveCriticalSection(&g_cs);
	}
	
	return 0;
}
之后运行该程序,就没有问题了。

三延展

1把全局的CString对象换成全局的int对象后,不存在上述问题

2在每个线程中加入Sleep(100);函数,暂时没有出现上述问题

3在Release版本下运行,竟然没有问题!

另,网上有这样一段话:

现象

当g_test为int,short char时,不存在多线程交叉读写错误的问题
当g_test为double, float, __int64时,存在多线程交叉读写错误的问题,对于__int64,当赋值小于0xFFFFFFFF时不出错,当大于0xFFFFFFFF时出错
当g_test为CString时,存在交叉读写错误,有时候程序崩溃
另:不加Sleep(1)机器卡死过,CPU占用率达到100%,4个核心占用率全满,可以保证运行在多核环境下

结论

1.对于int,short,char,BOOL等小于等于4字节的简单数据类型,如果无逻辑上的先后关系,多线程读写可以完全不用加锁
2.尽管float为4字节,多线程访问时也需要加锁
3.对于大于4字节的简单类型,比如double,__int64等,多线程读写必须加锁。
4.对于所有复杂类型,比如类,结构体,容器等类型必须加锁

综合来看,加锁就是了。


你可能感兴趣的:(随笔)