簡體   English   中英

std :: thread thread在對象中分離出來,什么時候終止?

[英]std::thread thread spun off in object, when does it terminate?

如果我在Bar的構造函數中關閉std::thread ,它什么時候停止運行? Bar實例被破壞時,它是否可以保證停止?

class Bar {

public:

Bar() : thread(&Bar:foo, this) {
}

...

void foo() {
  while (true) {//do stuff//}

}

private:
  std::thread thread;

};

編輯:如何正確終止析構函數中的std::thread

如果我在Bar的構造函數中關閉std :: thread,它什么時候停止運行?

只要它執行你提供的調用,或者程序終止,線程就會運行。

當Bar實例被破壞時,它是否可以保證停止?

不。為了保證這一點,在Bar析構函數中調用std::thread::join

實際上,如果你沒有在Bar::~Bar之前調用thread::jointhread::detach ,那么你的應用程序將通過自動調用std::terminatestd::terminate 所以你必須要么join (優先)或detach (少推薦)。

你還想在對象析構函數上調用therad::join ,因為生成的線程依賴於對象是活的 ,如果在你的線程處理該對象時對象被破壞 - 你正在使用被破壞的對象而你將有未定義的行為在你的代碼中。

簡短的回答:是的,不是。 是的,線程結束,但不是通常的方式(殺死線程),而是由於std::terminate調用退出的主線程。

答案很長:只有在底層函數( 線程 )執行完畢后才能安全地破壞線程 這可以通過兩種方式完成

  • 調用join() ,等待線程完成(在你的情況下,永遠不會)
  • 調用detach() ,它將線程與主線程分離(在這種情況下,線程將在主線程關閉時結束 - 當程序終止時)。

如果在所有這些條件都不適用的情況下調用析構函數,則調用std::terminate

  • 它是默認構造的

  • 它被移走了

  • 已調用join()

  • 已經調用了detach()

C ++線程工具包含用於終止線程的內置機制。 相反,你必須自己決定:a)一個機制來通知線程它應該終止,b)你不關心線程在進程終止時在操作中被中止並且操作系統只是停止運行它的線程任何更多。

std::thread對象不是線程本身,而是包含線程的描述符/句柄的不透明對象,因此理論上它可以在不影響線程的情況下被銷毀,並且存在支持和反對線程自動終止的參數。 相反,作為妥協,它是這樣做的,以便在線程保持運行和附加時銷毀std::thread對象將導致應用程序終止。

結果,在它的析構函數中有一些代碼如下:

~thread() {
    if (this->joinable())
        std::terminate(...);
}

這是一個使用簡單原子變量並在線程中檢查它的示例。 對於更復雜的情況,您可能需要考慮condition_variable或其他更復雜的信令機制。

#include <thread>
#include <atomic>
#include <chrono>
#include <iostream>

class S {
    std::atomic<bool> running_;
    std::thread thread_;
public:
    S() : running_(true), thread_([this] () { work(); }) {}
    void cancel() { running_ = false; }
    ~S() {
        if ( running_ )
            cancel();
        if ( thread_.joinable() )
            thread_.join();
    }
private:
    void work() {
        while ( running_ ) {
            std::this_thread::sleep_for(std::chrono::milliseconds(500));
            std::cout << "tick ...\n";
            std::this_thread::sleep_for(std::chrono::milliseconds(500));
            std::cout << "... tock\n";
        }
        std::cout << "!running\n";
    }
};

int main()
{
    std::cout << "main()\n";
    {
        S s;
        std::this_thread::sleep_for(std::chrono::milliseconds(2750));
        std::cout << "end of main, should see a tock and then end\n";
    }
    std::cout << "finished\n";
}

現場演示: http//coliru.stacked-crooked.com/a/3b179f0f9f8bc2e1

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM