【发布时间】:2015-12-10 15:14:38
【问题描述】:
我想避免从进程中的线程多次调用 RegisterClassEx()。为此,我修改了现有功能,如下所示。
当前代码结构对使用替代方法来实现线程安全性施加了限制,因此目前我试图坚持最少的更改。
请让我知道您对以下代码的看法。
foo()
{
static ATOM atom = 0;
if( atom == 0 )
{
{
EnterCriticalSection(&m_CSRegisterClassEx);
if( atom == 0 )
{
atom = RegisterClassEx(&tCls);
if( atom == 0)
{
ERROR(L"RegisterClassEx failed! );
LeaveCriticalSection(&m_CSRegisterClassEx);
return 0;
}
else
{
ERROR(L"RegisterClassEx good!");
LeaveCriticalSection(&m_CSRegisterClassEx);
return atom;
}
}
}
}
else
{
ERROR(L"using atom[%ld] from last call!", atom);
return atom;
}
}
在此处输入代码
【问题讨论】:
-
您在
atom上存在明显的数据竞争,导致您的代码格式不正确。 -
当您从多个线程访问一个值时,需要在显式互斥体中保护它以确保互斥,或者包装在 std::atomic 中。
-
如果那是我的代码,我会编写一个函数
ATOM get_atom()来完成所有RegisterClassEx的内容减去关键部分的内容,然后只写ATOM foo(){ static ATOM atom = get_atom(); return atom;}并依赖 magic statics (requires VS 2015)。 -
我相信多个线程可以找到第一个 if 语句为真,其中只有一个会通过 EnterCriticalSection() 然后注册该类,而其他线程则在睡眠队列中。当他们醒来并进入临界区时,我做的第一件事就是再次检查 atom 的值,这将被更新。这够了吗?我缺少哪个代码路径?
-
代码不安全。这是双重检查锁定模式的实现,为了安全起见,您需要使用内存屏障(考虑使用
std::atomic<int> ATOM而不是int ATOM)。
标签: c++ multithreading winapi thread-safety