這是一個簡單的(也可能是天真的)線程池的實現。通知線程退出
我想知道是否,鑑於下面的方法,有一個很好的方式來主動通知線程池線程退出,而不是在每次超時後檢查布爾值mStopped
。
我明白,有更好的方法來實現一個線程池 - 但我仍然有興趣看看下面的代碼是否可以改進,而不會從根本上改變它。
我很高興聽到一般性建議......不一定修復下面的代碼......問題實際上是關於信號/等待線程,線程池只是爲了給出一些上下文。
我用gcc 4.4.6(所以下面的一些語法是有點過時了),而且代碼與g++ --std=c++0x main.cc -pthread
#include <vector>
#include <mutex>
#include <thread>
#include <deque>
#include <condition_variable>
#include <functional>
using namespace std;
struct ThreadPool;
struct Worker {
ThreadPool& mThreadPool;
Worker(ThreadPool& threadPool) : mThreadPool(threadPool) {}
void operator()();
};
struct ThreadPool {
vector<thread> mWorkers;
deque<function<void()>> mTasks;
bool mStopped; // not atomic
mutex mMutex;
condition_variable mCond;
ThreadPool() : mStopped(false) {
for (size_t i = 0; i < 5; i++)
mWorkers.push_back(thread(Worker(*this)));
}
~ThreadPool() { stop(); }
void stop() {
if (!mStopped) {
mStopped = true;
for (auto it = mWorkers.begin(); it != mWorkers.end(); ++it)
if (it->joinable()) it->join();
}
}
bool canBreakFromWait() const { return !mTasks.empty(); }
void enqueue(function<void()> f) {
if (mStopped) return;
unique_lock<mutex> lck(mMutex);
mTasks.push_back(f);
mCond.notify_one();
}
};
void Worker::operator()() {
while (true) {
unique_lock<mutex> lck(mThreadPool.mMutex);
mThreadPool.mCond.wait_for(lck, chrono::seconds(1), bind(&ThreadPool::canBreakFromWait, &mThreadPool));
if (mThreadPool.mStopped) break;
auto task = mThreadPool.mTasks.front();
mThreadPool.mTasks.pop_front();
lck.unlock();
task();
}
}
void doWork(int data) {}
int main() {
ThreadPool threadPool;
for (auto i = 0; i < 50; i++)
threadPool.enqueue(bind(doWork, i));
threadPool.stop();
}
必須對所有對'mStopped'的訪問進行同步。 –
謝謝詹姆斯。我同意他們應該是普遍的,但我不認爲這會影響給出的例子(即在這種情況下誤解mStopped不是災難性的)。如我錯了請糾正我。 –
標準說未定義的行爲。在理論上,在更低的層面上,你可能永遠不會在其中一個線程中看到它「真實」。 (在實踐中......) –