[英]how to insert vector only once in multiple thread
I have below code snippet. 我有下面的代码片段。
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
will be called by multiple thread, and I want g_vec
will be inserted items only once which is a bit similar as singleton instance
. func
将由多个线程调用,我希望g_vec
仅插入一次项目,这与singleton instance
有点类似。 And about singleton instance
, I found there is a DCLP
issue. 关于
singleton instance
,我发现存在DCLP
问题。
Question : 问题 :
1. My above code snippet is thread safe, is it has DCLP issue? 1.我上面的代码段是线程安全的,是否存在DCLP问题?
2. If not thread safe, how to modify it? 2.如果不是线程安全的,该如何修改?
Your code has a data race. 您的代码存在数据争用。
The first check outside the lock is not synchronized with the insertion inside the lock. 锁外部的第一张支票与锁内部的插入不同步。 That means, you may end up with one thread reading the vector (through
.empty()
) while another thread is writing the vector (through .insert()
), which is by definition a data race and leads to undefined behavior. 这意味着,您可能最终会遇到一个线程(通过
.empty()
)读取向量的情况,而另一个线程正在通过.insert()
)写入向量的结果, 根据定义 ,这是一个数据竞争,并导致未定义的行为。
A solution for exactly this kind of problem is given by the standard in form of call_once
. 标准以
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( ... ); });
}
In your example, it could happen that second reentrant thread will find a non empty half initialized vector, that it's something that you won`t want anyway. 在您的示例中,有可能第二个可重入线程将找到一个非空的半初始化向量,这是您始终不想要的。 You should use a flag, and mark it when initialization job is completed.
您应该使用一个标志,并在初始化作业完成时对其进行标记。 Better a standard one, but a simple static int will do the job as well
更好的是一个标准的,但是一个简单的static 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()
}
...
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.