2015-10-18 109 views
2

我有Java線程的經驗,但想要學習如何在C++ 11中使用它們。我試圖做一個簡單的線程池,線程創建一次,可以要求執行任務。C++ 11線程未加入

#include <thread> 
#include <iostream> 

#define NUM_THREADS 2 

class Worker 
{ 
public: 
    Worker(): m_running(false), m_hasData(false) 
    { 

    }; 
    ~Worker() {}; 

    void execute() 
    { 
     m_running = true; 

     while(m_running) 
     { 
      if(m_hasData) 
      { 
       m_system(); 
      } 
      m_hasData = false; 
     } 
    }; 

    void stop() 
    { 
     m_running = false; 
    }; 

    void setSystem(const std::function<void()>& system) 
    { 
     m_system = system; 
     m_hasData = true; 
    }; 

    bool isIdle() const 
    { 
     return !m_hasData; 
    }; 
private: 
    bool m_running; 
    std::function<void()> m_system; 
    bool m_hasData; 
}; 

class ThreadPool 
{ 
public: 
    ThreadPool() 
    { 
     for(int i = 0; i < NUM_THREADS; ++i) 
     { 
      m_threads[i] = std::thread(&Worker::execute, &m_workers[i]); 
     } 
    }; 
    ~ThreadPool() 
    { 
     for(int i = 0; i < NUM_THREADS; ++i) 
     { 
      std::cout << "Stopping " << i << std::endl; 
      m_workers[i].stop(); 
      m_threads[i].join(); 
     } 
    }; 

    void execute(const std::function<void()>& system) 
    { 
     // Finds the first non-idle worker - not really great but just for testing 
     for(int i = 0; i < NUM_THREADS; ++i) 
     { 
      if(m_workers[i].isIdle()) 
      { 
       m_workers[i].setSystem(system); 
       return; 
      } 
     } 
    }; 
private: 
    Worker m_workers[NUM_THREADS]; 
    std::thread m_threads[NUM_THREADS]; 
}; 

void print(void* in, void* out) 
{ 
    char** in_c = (char**)in; 
    printf("%s\n", *in_c); 
} 

int main(int argc, const char * argv[]) { 
    ThreadPool pool; 
    const char* test_c = "hello_world"; 
    pool.execute([&]() { print(&test_c, nullptr); }); 
} 

的這個輸出是:

hello_world 
Stopping 0 

之後,主線程暫停,因爲它在等待第一個線程加入(ThreadPool中的析構函數)。出於某種原因,工作人員的m_running變量未設置爲false,這會使應用程序無限期地運行。

+0

它在我的電腦上正常工作。用visual studio構建2013 –

+0

@DavidHaim:代碼包含未定義的行爲。代碼的行爲如預期是完全可能的。 Howerver因爲對共享變量m_running的訪問不同步,編譯器可以假定它不會在工作線程中更改。即使編譯器沒有對其進行優化,CPU也可以採取相同的措施,並且從不更新m_running的高速緩存條目,並使用其他CPU或內核中更改後的值更新。所以最終的行爲取決於你的編譯器,它的優化和你的CPU。 – Finn

回答

5

Worker::stop成員m_running寫在主線程中,而它在另一個線程中執行讀取。這是未定義的行爲。您需要保護來自不同線程的讀/寫訪問。在這種情況下,我會建議使用std::atomic<bool>作爲m_running

編輯:同樣適用於m_hasData

+1

+1。只需添加爲什麼這是必要的解釋在https://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Herb-Sutter-atomic-Weapons-1-of-2 –

+0

我會必須爲所有*創建/讀取/寫入一個線程並在另一個線程中執行此操作?如果我將任務添加到線程池,這些任務需要是原子的還是使用互斥鎖? – RaptorDotCpp