我想写一个包装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