[英]Thread calling thread.detach() on itself when destroying object which contains that thread
[英]Unexpected behavior when std::thread.detach is called
我一直在嘗試更好地理解C ++線程,並以此編寫了以下示例:
#include <functional>
#include <iostream>
#include <thread>
class Test {
public:
Test() { x = 5; }
void act() {
std::cout << "1" << std::endl;
std::thread worker(&Test::changex, this);
worker.detach();
std::cout << "2" << std::endl;
}
private:
void changex() {
std::cout << "3" << std::endl;
x = 10;
std::cout << "4" << std::endl;
}
int x;
};
int main() {
Test t;
t.act();
return 0;
}
對我來說,當使用與-pthread
鏈接的g++
編譯時,我應該得到以下輸出:
1
2
3
4
因為cout
呼叫是按該順序進行的。 但是,輸出不一致。 1和2總是按順序打印,但有時3和4會省略或打印兩次。 即12
, 123
, 1234
,或12344
我的工作原理是,主線程在工作線程開始工作或完成之前退出,從而導致輸出的遺漏。 我可以立即想到一個解決此問題的方法,即創建一個全局布爾變量來表示工作線程何時完成,即主線程在退出之前等待狀態更改。 這樣可以減輕問題。
但是,在我看來,這就像是一種高度混亂的方法,可能具有更干凈的解決方案,尤其是對於這樣的問題(可能經常在線程中出現)。
對於在C ++中使用原始pthreads和在std :: thread中包裝的pthreads而言,這只是一些通用建議,這是獲得可讀性,可理解性和可調試行為的最佳方法:使線程同步和生存期管理明確化。 即避免使用pthread_kill,pthread_cancel,並且在大多數情況下,避免分離線程,而是進行顯式聯接。
我喜歡的一種設計模式是使用std原子標志。 當主線程想要退出時,它將原子標志設置為true。 工作線程通常在一個循環中完成其工作,並合理地頻繁檢查原子標志,例如,每循環一圈檢查一次。 當他們發現主要人員命令他們退出時,他們清理並返回。 然后,主線程與所有工作人員加入:s。
在某些特殊情況下,需要格外小心,例如,當一個工作人員陷入阻塞的系統調用和/或C庫函數中時。 通常,該平台提供了無需使用pthread_cancel即可擺脫此類阻塞調用的方法,因為線程取消在C ++中非常不利。 如何避免阻塞的一個示例是getaddrinfo_a的Linux聯機幫助頁,即異步網絡地址轉換。
另一種不錯的設計模式是工人在例如select()中睡覺時。 然后,您可以在main和worker之間添加一個額外的控制管道。 Main通過send()向工作人員發出退出信號:在管道上占用一個字節,因此如果工人在select()中睡眠,則將其喚醒。
如何完成此操作的示例:
#include <functional>
#include <iostream>
#include <thread>
class Test {
std::thread worker; // worker is now a member
public:
Test() { x = 5; } // worker deliberately left without a function to run.
~Test()
{
if (worker.joinable()) // worker can be joined (act was called successfully)
{
worker.join(); // wait for worker thread to exit.
// Note destructor cannot complete if thread cannot be exited.
// Some extra brains needed here for production code.
}
}
void act() {
std::cout << "1" << std::endl;
worker = std::thread(&Test::changex, this); // give worker some work
std::cout << "2" << std::endl;
}
// rest unchanged.
private:
void changex() {
std::cout << "3" << std::endl;
x = 10;
std::cout << "4" << std::endl;
}
int x;
};
int main() {
Test t;
t.act();
return 0;
} // test destroyed here. Destruction halts and waits for thread.
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.