删除std::lock_guard相对于其他堆栈分配对象的顺序/速度
delete order/speed of std::lock_guard relative to other stack-allocated objects?
据我所知,从lock_guard被删除到函数(在另一个线程中运行(实际返回之间有相当长的时间。请参阅TEST(…(中的以下注释
bool bDone = false;
void run_worker(Foo* f) {
f->Compute();
bDone = true;
}
TEST(FooTest,ThreadFoo) {
Foo* f = makeFoo();
std::thread worker( run_worker, f );
worker.detach();
micro_wait(100); // wait for N microseconds
f->Reset(); // should block until Compute() is done
// !!?? Why is this necessary !?!?
int k=0;
while(++k<500 && !bDone)
micro_wait(100);**
EXPECT_TRUE(bDone); // Fails even with a single micro_wait(100)!
}
什么时候/为什么会有这样的时间流逝,有什么好的解释吗介于f->Compute((完成和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
}
bDone
没有同步。
编译器很可能在bDone
的值为false时将其加载到寄存器中,然后继续使用寄存器缓存的版本,而不是从内存中获取更新的版本。或者,您的指令可能会被重新排序,以便在释放锁后bDone
被设置为false。
正确的方法是使用std::atomic<bool>
。工作线程可以通过对bDone.store(true)
的调用来更新它,而等待线程可以通过调用bDone.load()
来读取它的最新值。
如果您想了解内存排序以帮助理解为什么需要原子,您可以通过使用acquire
和release
排序来进一步改进这一点(尽管对于单元测试来说,这并不重要(。
除此之外,你真正应该做的是加入你的工人线程。连接会一直阻塞到线程结束,因此可以确保Compute
函数已完成执行。如果你担心它可能会永远运行(或运行太久(,我建议使用boost::thread
而不是std::thread
,因为它提供了一个timed_join
函数,在指定的时间段后停止等待线程。
相关文章:
- 有没有一种方法可以使用placement new将堆叠对象分配给分配的内存
- C++ 如何在将新对象分配给另一个对象时创建新对象
- 为什么我可以在不重载 "=" 运算符的情况下将一个对象分配给另一个对象?
- 为对象分配整数.输出将是什么?
- C++ 使用枚举类对象分配 std::map 值
- 如何在C++中为增加但记住删除先前对象的对象分配唯一标识符
- 我重载了 << 和 = 运算符。为什么当我将一个对象分配给另一个对象并尝试打印它时,我会被打印出来?
- 为什么将两个对象分配给另一个对象后,两个对象不一样?
- 有没有办法在同名类 (c++) 中为对象分配一个指针变量
- 如何使用函数(而不是构造函数)将派生类对象分配给基类指针
- 是否可以使用 malloc 为类对象分配内存?
- 将对象分配给数组C++
- 我们可以在cpp中为对象分配函数吗
- 为模板参数类型中的新对象分配内存
- 我无法将对象分配给对象数组
- 对象分配-成员函数的使用无效错误
- 将派生对象分配给函数内的基类指针
- Arduino ESP32如何将BLEUUID对象分配到字符串中
- Rapidjson将密钥值从一个文档对象分配到另一个文档对象
- 奇怪的对象分配行为C