我想寫一個包裝std :: thread的類,它的行爲像std :: thread,但每次我需要處理某些異步時都沒有實際分配一個線程。原因是我需要在不允許動態分配的上下文中使用多線程,而且我也不想要創建std :: thread的開銷。編寫一個活着的線程
取而代之,我想要一個線程在循環中運行並等待它可以開始處理。客戶呼叫invoke
喚醒線程。線程鎖定一個互斥鎖,它是否正在處理並再次入睡。函數join
的行爲類似於std :: thread :: join,直到線程釋放鎖(即再次入睡)爲止。
我想我得到了課程,但由於多線程的普遍缺乏經驗,我想問問有沒有人可以發現比賽條件,或者如果我使用的方法被認爲是「好風格」。例如,我不確定是否臨時鎖定互斥體是一種體面的方式來「加入」線程。
編輯 我發現了另一個競爭條件:調用join
後直接invoke
時,沒有理由線程已經鎖定互斥體,因此直到線程進入睡眠狀態鎖定的join
調用者。爲了防止這種情況,我必須爲invoke計數器添加一個檢查。
頭
#pragma once
#include <thread>
#include <atomic>
#include <mutex>
class PersistentThread
{
public:
PersistentThread();
~PersistentThread();
// set function to invoke
// locks if thread is currently processing _func
void set(const std::function<void()> &f);
// wakes the thread up to process _func and fall asleep again
// locks if thread is currently processing _func
void invoke();
// mimics std::thread::join
// locks until the thread is finished with it's loop
void join();
private:
// intern thread loop
void loop(bool *initialized);
private:
bool _shutdownRequested{ false };
std::mutex _mutex;
std::unique_ptr<std::thread> _thread;
std::condition_variable _cond;
std::function<void()> _func{ nullptr };
};
源文件
#include "PersistentThread.h"
PersistentThread::PersistentThread()
{
auto lock = std::unique_lock<std::mutex>(_mutex);
bool initialized = false;
_thread = std::make_unique<std::thread>(&PersistentThread::loop, this, &initialized);
// wait until _thread notifies, check bool initialized to prevent spurious wakeups
_cond.wait(lock, [&] {return initialized; });
}
PersistentThread::~PersistentThread()
{
{
std::lock_guard<std::mutex> lock(_mutex);
_func = nullptr;
_shutdownRequested = true;
// wake up and let join
_cond.notify_one();
}
// join thread,
if (_thread->joinable())
{
_thread->join();
}
}
void PersistentThread::set(const std::function<void()>& f)
{
std::lock_guard<std::mutex> lock(_mutex);
this->_func = f;
}
void PersistentThread::invoke()
{
std::lock_guard<std::mutex> lock(_mutex);
_cond.notify_one();
}
void PersistentThread::join()
{
bool joined = false;
while (!joined)
{
std::lock_guard<std::mutex> lock(_mutex);
joined = (_invokeCounter == 0);
}
}
void PersistentThread::loop(bool *initialized)
{
std::unique_lock<std::mutex> lock(_mutex);
*initialized = true;
_cond.notify_one();
while (true)
{
// wait until we get the mutex again
_cond.wait(lock, [this] {return _shutdownRequested || (this->_invokeCounter > 0); });
// shut down if requested
if (_shutdownRequested) return;
// process
if (_func) _func();
_invokeCounter--;
}
}
聽起來像你想要[線程池](https://en.wikipedia.org/wiki/Thread_pool) – NathanOliver
也許這應該被張貼在Codereview SE? –
@NathanOliver我第二。只需在開始時立即創建一些線程,然後使用它們。 – Carcigenicate