2015-10-18 72 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