我有以下代码段。
std::vector<int> g_vec;
void func()
{
//I add double check to avoid thread need lock every time.
if(g_vec.empty())
{
//lock
if(g_vec.empty())
{
//insert items into g_vec
}
//unlock
}
...
}
func
将由多个线程调用,我希望g_vec
只插入一次与singleton instance
有点相似的项目。关于singleton instance
,我发现存在DCLP
问题。
问题:
1.我上面的代码片段是线程安全的,它有DCLP问题吗?
2.如果不是线程安全,如何修改它?
答案 0 :(得分:3)
您的代码有数据竞争。
锁外的第一次检查与锁内的插入不同步。这意味着,你可能最终得到一个线程读取向量(通过.empty()
),而另一个线程正在写向量(通过.insert()
),这是by definition数据竞争并导致未定义的行为。
标准以call_once
的形式给出了解决这类问题的方法。
#include<mutex>
std::vector<int> g_vec;
std::once_flag g_flag;
void func()
{
std::call_once(g_flag, [&g_vec](){ g_vec.insert( ... ); });
}
答案 1 :(得分:-1)
在你的例子中,可能会发生第二个可重入的线程将找到一个非空的半初始化向量,这是你无论如何都不想要的东西。您应该使用标志,并在初始化作业完成时将其标记。更好的标准,但一个简单的静态int也可以完成这项工作
std::vector<int> g_vec;
void func()
{
//I add double check to avoid thread need lock every time.
static int called = 0;
if(!called)
{
lock()
if(!called)
{
//insert items into g_vec
called = 1;
}
unlock()
}
...
}