[英]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
加載到寄存器中,然后繼續使用寄存器緩存的版本,而不是從內存中獲取更新的版本。 或者,您的指令可能會重新排序,以便在釋放鎖定后將 bDone
設置為false。
解決此問題的正確方法是使用std::atomic<bool>
。 輔助線程可以通過調用bDone.store(true)
對其進行更新,而等待線程可以通過調用bDone.load()
讀取其最新值。
如果您想讀入內存順序以幫助理解為什么需要原子,則可以通過使用acquire
和release
順序來進一步改進此功能(盡管對於單元測試來說,這並不重要)。
除此之外,您真正應該做的是加入工作線程。 直到線程結束,聯接才會阻塞,因此可以確保您的Compute
函數已完成執行。 如果您擔心它可能永遠運行(或運行時間太長),建議使用boost::thread
而不是std::thread
,因為它提供了timed_join
函數,該函數在指定時間段后不再等待線程時間。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.