簡體   English   中英

C ++ 11線程不適用於虛擬成員函數

[英]C++11 thread doesn't work with virtual member function

我正在嘗試讓類運行一個線程,它將在循環中調用名為Tick()的虛擬成員函數。 然后我嘗試派生一個類並覆蓋base :: Tick()。

但是在執行時,程序只調用基類的Tick而不是覆蓋它。 任何解決方案

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

using namespace std;

class Runnable {
 public:
  Runnable() : running_(ATOMIC_VAR_INIT(false)) {

   }
  ~Runnable() { 
    if (running_)
      thread_.join();
  }
  void Stop() { 
    if (std::atomic_exchange(&running_, false))
      thread_.join();
  }
  void Start() {
    if (!std::atomic_exchange(&running_, true)) {
      thread_ = std::thread(&Runnable::Thread, this);
    }
  }
  virtual void Tick() {
    cout << "parent" << endl;
  };
  std::atomic<bool> running_;

 private:
  std::thread thread_;
  static void Thread(Runnable *self) {
    while(self->running_) {
      self->Tick();
      std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
  }
};

class Fn : public Runnable {
 public:
  void Tick() {
    cout << "children" << endl;
  }
};

int main (int argc, char const* argv[])
{
  Fn fn;
  fn.Start();
  return 0;
}

輸出:

parent

在完成使用之前,您不能讓對象超出范圍! return 0; main結束時fn超出范圍。 因此,當你開始調用tick ,不能保證對象甚至不再存在。

~Runnable的邏輯完全被破壞。析構函數內部太遲了 - 對象已經至少部分被破壞了。)

使用繼承與父作為線程的控件實現函數的子項的方法通常是一個壞主意。 這種方法的常見問題來自構建和破壞:

  • 如果線程是從父(控件)中的構造函數啟動的,則它可能在構造函數完成之前開始運行,並且線程可能在完整構造完整對象之前調用虛函數

  • 如果線程在父類的析構函數中停止,那么在控件加入線程時,線程正在對不再存在的對象執行方法。

在你的特殊情況下,你正在遇到第二種情況。 程序開始執行,並在main中啟動第二個線程。 此時主線程和新啟動之間存在競爭,如果新線程更快(不太可能,因為啟動線程是一項昂貴的操作),它將調用將被調度到最終覆蓋的成員方法Tick Fn::Tick

但是如果主線程更快,它將退出main的范圍,並且它將開始破壞對象,它將完成對Fn對象的破壞,並且在構造Runnable期間它將join線程。 如果主線程足夠快,它將在第二個線程之前進入join ,並在那里等待第二個線程在現在最終的覆蓋器上運行Tick ,這個覆蓋器是Runnable::Tick 請注意,這是未定義的行為 ,並且無法保證,因為第二個線程正在訪問正在銷毀的對象。

此外,還有其他可能的排序,例如,第二個線程可以在主線程開始銷毀之前調度到Fn::Tick ,但可能在主線程銷毀Fn子對象之前沒有完成該函數,在這種情況下你的第二個線程將在死對象上調用成員函數。

您應該遵循C ++標准中的方法:將控件邏輯分開,完全構造將運行的對象並在構造期間將其傳遞給線程。 請注意,這是Java的Runnable的情況,建議使用它來擴展Thread類。 請注意,從設計的角度來看,這種分離是有意義的: 線程對象管理執行,而runnable是要執行的代碼。 線程不是股票代碼 ,而是控制股票代碼執行的內容。 在你的代碼中, Runnable不是可以運行的東西,而是運行其他碰巧從它派生的對象。

暫無
暫無

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

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