這兩天花時間嘗試實現了一下線程池,本來是想完全自己寫的,但是寫着寫着就去參考muduo庫的線程池了,實現思路和muduo庫的線程池一模一樣。我嘗試着在不考慮線程安全的情況下對muduo庫線程池的實現做一下簡述。
1. 核心思想
2. 兩個條件變量
放置任務:
void ThreadPool::run(const Task& task) // 其他線程給線程池塞任務的接口
{
if (threads_.empty()) // 如果線程列表爲空,那就只能自己執行了
{
task(); // 執行回調函數(函數指針)
}
else
{
MutexLockGuard lock(mutex_); // 鎖住臨界區
while (isFull()) // 判斷當前任務列表是否已經滿了
{
notFull_.wait(); // 如果滿了,那就等待任務線程把任務取走後通知當前線程可以放置任務了
}
assert(!isFull());
queue_.push_back(task);
notEmpty_.notify(); // 通知還在阻塞狀態的任務線程,現在可以試試看獲取任務
}
}
獲取任務:
ThreadPool::Task ThreadPool::take() // 線程池中的線程從任務列表中獲取任務
{
MutexLockGuard lock(mutex_);
// always use a while-loop, due to spurious wakeup
while (queue_.empty() && running_) // 當任務列表未空的時候才阻塞,不然直接獲取任務列表中的任務
{
notEmpty_.wait(); // 喚醒之後馬上又會上鎖
}
Task task;
if (!queue_.empty())
{
task = queue_.front(); // 獲取任務
queue_.pop_front(); // 獲取任務之後從任務列列表中將其刪除(互斥鎖已經將臨界資源保護好)
if (maxQueueSize_ > 0)
{
notFull_.notify(); // 取完任務之後,告訴給任務的線程當前任務列表未滿(如果給任務的線程卡在等待通知的地方)
}
}
return task; // 將獲取到的任務返回給任務線程
}
3. 關閉線程池
void ThreadPool::stop()
{
{
MutexLockGuard lock(mutex_);
running_ = false; // 改變線程池邏輯狀態
notEmpty_.notifyAll(); // 通知所有線程對象來看一眼running_的狀態
}
for_each(threads_.begin(),
threads_.end(),
boost::bind(&muduo::Thread::join, _1)); // 挨個等待線程對象退出線程
}
ThreadPool::~ThreadPool()
{
if (running_)
{
stop();
}
}
另外說明一點,muduo線程池使用智能指針來管理線程對象的。