2016-05-26 4 views
0

私は単純なスレッドプールの実装を持っています。実装は以下の通りですプッシュが成功したにもかかわらず、プッシュされたアイテムでスレッドプールキューが更新されていません

問題は、キューに項目を挿入したときにスレッドプールの機能に反映されない場合です。void worker_thread()つまりworker_thread()のif(work_queue.try_pop(task)関数は常に失敗し、スレッドによってタスクが選択されません。 私は間違っていることを指摘できますか?

ありがとうございます。

template<typename T> 
class threadsafe_queue 
{ 
private: 
    mutable std::mutex mut; 
    std::queue<T> data_queue; 
    std::condition_variable data_cond; 
public: 
    threadsafe_queue() 
    {} 

    void push(T new_value) 
    { 
     std::lock_guard<std::mutex> lk(mut); 
     data_queue.push(std::move(new_value)); 
     data_cond.notify_one(); 
    } 

    void wait_and_pop(T& value) 
    { 
     std::unique_lock<std::mutex> lk(mut); 
     data_cond.wait(lk, [this]{return !data_queue.empty(); }); 
     value = std::move(data_queue.front()); 
     data_queue.pop(); 
    } 

    std::shared_ptr<T> wait_and_pop() 
    { 
     std::unique_lock<std::mutex> lk(mut); 
     data_cond.wait(lk, [this]{return !data_queue.empty(); }); 
     std::shared_ptr<T> res(
      std::make_shared<T>(std::move(data_queue.front()))); 
     data_queue.pop(); 
     return res; 
    } 

    bool try_pop(T& value) 
    { 
     std::lock_guard<std::mutex> lk(mut); 
     if (data_queue.empty()) 
      return false; 
     value = std::move(data_queue.front()); 
     data_queue.pop(); 
    } 

    std::shared_ptr<T> try_pop() 
    { 
     std::lock_guard<std::mutex> lk(mut); 
     if (data_queue.empty()) 
      return std::shared_ptr<T>(); 
     std::shared_ptr<T> res(
      std::make_shared<T>(std::move(data_queue.front()))); 
     data_queue.pop(); 
     return res; 
    } 

    bool empty() const 
    { 
     std::lock_guard<std::mutex> lk(mut); 
     return data_queue.empty(); 
    } 
}; 

class thread_pool 
{ 
    threadsafe_queue<std::function<void()>> work_queue; 
    std::atomic<bool> done; 
    int thread_count; 
    std::vector<std::thread> threads; 

    void worker_thread() 
    { 
     while (!done) 
     { 
      std::function<void()> task; 
      if (work_queue.try_pop(task)) // here work_queue is always empty. 
      { 
       task(); 
      } 
      else 
      { 
       std::this_thread::yield(); 
      } 
     } 
    } 
public: 
    thread_pool(unsigned thread_count = 5) : done(false), thread_count(thread_count) 
    { 
     try 
     { 
      for (unsigned i = 0; i < thread_count; ++i) 
      { 
       threads.emplace_back(std::thread(&thread_pool::worker_thread, this)); 
      } 
     } 
     catch (...) 
     { 
      done = true; 
      throw; 
     } 
    } 

    ~thread_pool() 
    { 
     done = true; 
     for (unsigned i = 0; i < thread_count; ++i) 
     { 
      threads[i].join(); 
     } 
    } 
    template <typename FunctionType> 
    void submit(FunctionType f) 
    { 
     work_queue.push(std::function<void()>(f)); // this shows proper size of queue after push. 
    } 
}; 

void fun() 
{ 
    cout << "hi"<<this_thread::get_id(); // this funciton is never being executed by thread pool. 
} 
template<class T> 
class A 
{ 
    private: 
    int x{ 3 }; 
public: 
     void fun(vector<string> &v) // this funciton is never being executed by thread pool. 
     { 
     std::cout << v[0].c_str() << endl; 
      x = 5; 
     } 

}

 int main() 
    { 
     thread_pool tp(2); 
     vector<string> v{ "1", "2" }; 
      A<int> a; 
      tp.submit([&] { a.fun(std::ref(v)); }); 
     tp.submit < void()>(fun); 
     std::this_thread::sleep_for(std::chrono::seconds(10)); 
     return 0; 
    } 
+0

制御 は非void型関数[-Wreturn型]の最後に到達しますか?第2に、あなたのキューに 'abort()'機能を持たせることは便利です。これは、キューが満了していることをスレッドに伝えるために使用できます。原則として、作業がないときは、何もする必要はありません。作業がない場合でも作業スレッドごとに1つのCPUが必要です。 – Yakk

答えて

4

あなたはtry_pop()方法でreturn true;の文が欠落しています。それに指すことになりますが有効になって警告やコンパイラでコンパイルする必要があります。

ttt.cpp:メンバ関数で 'ブールthreadsafe_queue :: try_pop [T =のstd ::機能付き](T &) ':TTTを。 CPP:57:5:警告:なぜ、あなたのワーカースレッドはスピン得、なぜ彼らは `wait_and_pop`をしていないされて

+0

あなたは私の一日を保存してくれてありがとう。 :) – user888270

関連する問題