簡體   English   中英

調用std :: thread.detach時發生意外行為

[英]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會省略或打印兩次。 121231234 ,或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.

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