C++ 删除std::lock\u guard相对于其他堆栈分配对象的顺序/速度?

C++ 删除std::lock\u guard相对于其他堆栈分配对象的顺序/速度?,c++,multithreading,c++11,locking,mutex,C++,Multithreading,C++11,Locking,Mutex,据我所知,从锁保护被删除到函数(在另一个线程中运行)实际返回之间有相当长的时间。请参阅测试(…)中的以下注释 boolbdone=false; 无效运行工人(Foo*f){ f->Compute(); bDone=true; } 测试(最足部、螺纹){ Foo*f=makeFoo(); std::线程工作线程(run_-worker,f); worker.detach(); 微等待(100);//等待N微秒 f->Reset();//应阻止,直到Compute()完成 //!!?为什么这是必要的

据我所知,从锁保护被删除到函数(在另一个线程中运行)实际返回之间有相当长的时间。请参阅测试(…)中的以下注释

boolbdone=false;
无效运行工人(Foo*f){
f->Compute();
bDone=true;
}
测试(最足部、螺纹){
Foo*f=makeFoo();
std::线程工作线程(run_-worker,f);
worker.detach();
微等待(100);//等待N微秒
f->Reset();//应阻止,直到Compute()完成
//!!?为什么这是必要的!?!?
int k=0;
当(++kCompute()完成并设置了bDone时?我的怀疑是,在清理Compute()中分配的基于堆栈的变量时,互斥锁会被解锁,但这纯粹是一个假设

计算和重置的存根如下所示:

void Foo::Compute() {
  std::lock_guard<std::mutex>  guard(m_Mutex);
  // ... allocate bunch of temporary stuff on stack, update *this
}

void Foo::Reset() {
  std::lock_guard<std::mutex>  guard(m_Mutex);
  // ... simpler stuff, clear
}
void Foo::Compute(){
std::锁定保护(m_互斥);
//…在堆栈上分配一堆临时内容,更新*此
}
void Foo::Reset(){
std::锁定保护(m_互斥);
//…更简单的东西,明白吗
}

没有同步
bDone

很可能编译器在值为false时将
bDone
加载到寄存器中,然后继续使用寄存器缓存的版本,而不是从内存获取更新的版本。或者,您的指令可能会重新排序,以便在释放锁后将
bDone
设置为false

正确的方法是使用
std::atomic
。工作线程可以通过调用
bDone.store(true)
来更新它,而等待的线程可以通过调用
bDone.load()
来读取它的最新值

如果您想读入内存顺序以帮助理解为什么需要原子,您可以通过使用
acquire
release
顺序进一步改进这一点(尽管对于单元测试来说,这并不重要)


除此之外,你真正应该做的是加入你的工作线程。一个加入阻止直到线程结束,这样你就可以确信你的
计算
函数已经完成了执行。如果你担心它会永远运行(或者运行太长时间),我建议使用
boost::thread
而不是
std::thread
,因为它提供了
timed_join
函数,在指定的时间段后停止等待线程。

没有
bDone
的同步

很可能编译器在值为false时将
bDone
加载到寄存器中,然后继续使用寄存器缓存的版本,而不是从内存获取更新的版本。或者,您的指令可能会重新排序,以便在释放锁后将
bDone
设置为false

正确的方法是使用
std::atomic
。工作线程可以通过调用
bDone.store(true)
来更新它,而等待的线程可以通过调用
bDone.load()
来读取它的最新值

如果您想读入内存顺序以帮助理解为什么需要原子,您可以通过使用
acquire
release
顺序进一步改进这一点(尽管对于单元测试来说,这并不重要)


除此之外,你真正应该做的是加入你的工作线程。一个加入阻止直到线程结束,这样你就可以确信你的
计算
函数已经完成了执行。如果你担心它会永远运行(或者运行太长时间),我建议使用
boost::thread
而不是
std::thread
,因为它提供了一个
timed_-join
函数,在指定的时间段后停止等待线程。

此代码看起来非常糟糕。
Compute
不能保证在
重置之前获得锁。
bDone在没有同步的情况下被访问。请享受您未定义的行为。好的,使用std::future+std::async;第一个micro_wait(100)可以更好地处理这种情况为了这个实验的目的,我阻止Reset首先获得锁。我只是想解释一下,在计算完成后为bool变量赋值的下一个语句如何在重置完成之前无法完成。这段代码看起来非常糟糕。不能保证
Compute
会在重置之前获得锁re
Reset
。同时
bDone
在不同步的情况下被访问。请享受您未定义的行为。对,使用std::future+std::async更好地处理这种情况;第一次微等待(100)为了这个实验的目的,我阻止Reset首先获得锁。我只是想解释一下,在计算完成之后,为bool变量赋值的下一个语句如何在Reset完成之前无法完成。是的,用原子+移除worker.detach()替换bool+在EXPECT_TRUE(bDone)导致良好行为之前插入worker.join。是的,将bool替换为原子+删除worker.detach()+在EXPECT_TRUE(bDone)导致良好行为之前插入worker.join。
void Foo::Compute() {
  std::lock_guard<std::mutex>  guard(m_Mutex);
  // ... allocate bunch of temporary stuff on stack, update *this
}

void Foo::Reset() {
  std::lock_guard<std::mutex>  guard(m_Mutex);
  // ... simpler stuff, clear
}