[英]c++ std::thread join() after thread is out of scope
我在這里第一次嘗試真正的問題。 我四處搜索,但沒有得到一個好的答案,所以如果這是一個 LMGTFY 問題,我深表歉意。
我正在為 c++ 應用程序引擎開發運行時循環。 這是一個標准的運行循環,我想在它自己的線程上執行,所以我可以控制執行時間而不依賴於操作系統特定的依賴項。 但是,我仍然想讓應用程序 window 與操作系統(在這種情況下為 Mac OSX)配合得很好,所以我有一個 objective-C 平台 object 將鍵/鼠標輸入傳遞給我的應用程序。 我的意圖是讓引擎通過原子 arrays 收集輸入,然后應用程序可以適當地響應來自操作系統的 Cocoa 回調,但我仍然可以保留對游戲循環的控制。
我遇到的問題是我當前的設置涉及一個啟動線程的方法,以及一個用於加入線程的單獨線程,因此達爾文可以對線程如何終止感到滿意。
//This is all in a class named engine.
id thread; // What type?
bool engineRunning;
int Engine::startYourEngines() {
engineRunning = true;
std::thread thread (engineLoop()); //How do I keep this thread?
}
int Engine::stopYourEngines() {
engineRunning = false;
thread.join(); //Thread is out of scope...or is it?
return 0;
}
int Engine::engineLoop() { //Only invoke this with Engine::startYourEngines()
engineThread = std::this_thread::get_id();
do {
// do things here!
}
} while (engineRunning);
return 0;
} /* Engine::engineLoop() */
我發現的所有示例都使用單個 function 來啟動線程並加入它。 我不想拆線,因為那只是一罐蠕蟲。 看起來獲取線程ID是一種識別線程的方法,但是我不知道如何使用ID再次找到線程。 這似乎是做我想做的最直接的方法。
似乎您想讓 object Engine
啟動一個工作thread
,並保存對該上下文的引用,以便在關閉時可以巧妙地關閉它。 如果您正在使用 C++20,您將使用jthread
和stop_token
來獲得超級整潔的 RAII。 如果您不使用 20(很可能),那么您必須自己動手。
我將此稱為停止標記習語,因為這就是 C++20 概念的名稱。 (我假設)您想要執行以下操作:
Engine
class 來處理工作線程的輸入和 output。Engine
時,打開您的工作線程,然后Engine
損壞。 如果您必須使用初始化類型方法 ( startYourEngines
) 和拆卸類型方法 ( stopYourEngines
),那么可能的解決方案如下所示。
// each start requires a paired stop
// may not double-start or double-stop
// starting and stopping are not thread-safe (may not run at the same time in different threads)
class Engine {
public:
Engine() : run_engine_{false}, worker_{} {}
void startYourEngines() {
run_engine_ = true; // tell the engine it's okay to run
worker_ = std::thread([&]{ engineLoop(); }); // start running the engine
}
void stopYourEngines() { // changed return type to void since you're not returning anything
run_engine_ = false; // tell the engine to stop running
worker_.join(); // wait for engine to stop running
}
void engineLoop() { // changed return type to void since you're not returning anything
while (run_engine_) {
// do things here!
}
}
};
在上面,每個startYourEngines
調用必須與stopYourEngines
調用配對。 您不能雙重啟動或雙重停止引擎,也不能同時調用startYourEngines
和stopYourEngines
。 有一些方法可以允許從不同線程開始和停止調用,但更容易禁止開發人員這樣做。
我個人覺得“init”和“teardown”風格的函數很可惡。 由於您的代碼最終看起來像
Engine engine;
engine.startYourEngines();
...do program stuff here until ready to shutdown...
engine.stopYourEngines();
一個更簡潔的替代方案是合並 RAII 風格的代碼,其中構造Engine
創建執行線程,而解構Engine
將其拆毀。 但是以上內容應該足以讓您繼續前進。
經過一天的折騰,這就是我想出的可行解決方案。
#include <iostream>
#include <thread>
#include <chrono>
class Engine {
public:
bool engineRunning = true;
void engineLoop() {
do {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::cout << "engine running\n";
} while (engineRunning);
}
std::thread engineThread;
Engine() {
engineThread = std::thread(&Engine::engineLoop, this);
}
~Engine() {
engineRunning = false;
if (engineThread.joinable()) engineThread.join();
}
};
int main(int argc, const char * argv[]) {
std::cout << "start program\n";
Engine *testThread = new Engine;
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "kill engine \n";
testThread->engineRunning = false;
std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout << "Done!\n";
return 0;
}
感謝您的評論和幫助! 隨意評論上面的代碼! 我總是想變得更好!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.