C++ 在派生类中管理线程生命周期
我有一个基类,它充当多个同步事件处理策略的接口。现在,我希望这些策略能够异步处理事件。为了尽量减少代码重构,每个策略都有自己的内部线程用于异步事件处理。我主要关心的是如何管理这个线程的生命周期。派生的strategies类在代码库中构建和销毁,因此很难在strategies类之外管理线程生命周期(开始/停止) 我最终得到了以下代码:C++ 在派生类中管理线程生命周期,c++,multithreading,boost,boost-thread,C++,Multithreading,Boost,Boost Thread,我有一个基类,它充当多个同步事件处理策略的接口。现在,我希望这些策略能够异步处理事件。为了尽量减少代码重构,每个策略都有自己的内部线程用于异步事件处理。我主要关心的是如何管理这个线程的生命周期。派生的strategies类在代码库中构建和销毁,因此很难在strategies类之外管理线程生命周期(开始/停止) 我最终得到了以下代码: #include <iostream> #include <cassert> #include <boost/shared_ptr.
#include <iostream>
#include <cassert>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
struct Base
{
virtual ~Base()
{
std::cout << "In ~Base()" << std::endl;
// For testing purpose: spend some time in Base dtor
boost::this_thread::sleep(boost::posix_time::milliseconds(1000));
}
virtual void processEvents() = 0;
void startThread()
{
if(_thread)
{
stopThread();
}
_thread.reset(new boost::thread(&Base::processEvents, this));
assert(_thread);
}
void stopThread()
{
if(_thread)
{
std::cout << "Interrupting and joining thread" << std::endl;
_thread->interrupt();
_thread->join();
_thread.reset();
}
}
boost::shared_ptr<boost::thread> _thread;
};
struct Derived : public Base
{
Derived()
{
startThread();
}
virtual ~Derived()
{
std::cout << "In ~Derived()" << std::endl;
// For testing purpose: make sure the virtual method is called while in dtor
boost::this_thread::sleep(boost::posix_time::milliseconds(1000));
stopThread();
}
virtual void processEvents()
{
try
{
// Process events in Derived specific way
while(true)
{
// Emulated interruption point for testing purpose
boost::this_thread::sleep(boost::posix_time::milliseconds(100));
std::cout << "Processing events..." << std::endl;
}
}
catch (boost::thread_interrupted& e)
{
std::cout << "Thread interrupted" << std::endl;
}
}
};
int main(int argc, char** argv)
{
Base* b = new Derived;
delete b;
return 0;
}
#包括
#包括
#包括
#包括
结构基
{
虚拟~Base()
{
std::cout在类被销毁时释放类创建的资源是一个好主意,即使其中一个资源是线程。但是,在析构函数中执行任何非平凡任务时,通常值得花时间全面检查其含义
析构函数
一般规则是:如果派生的
对象位于从另一个异常解绕的堆栈上,并且派生的::~Derived()
抛出异常,则将调用std::terminate()
,终止应用程序。而派生的:~Derived())没有明确抛出异常,重要的是要考虑它调用的一些函数可能会抛出,例如.
如果std::terminate()
是所需的行为,则不需要进行任何更改。但是,如果std::terminate()
不是所需的行为,则捕获boost::thread\u并抑制它
try
{
_thread->join();
}
catch (const boost::thread_interrupted&)
{
/* suppressed */
}
遗产
似乎继承被用于代码重用,并通过将异步行为隔离到Base
层次结构内部来最小化代码重构。然而,一些样板逻辑也在Dervied
中。我建议,由于从Base
派生的类已经必须更改考虑聚合或最小化这些类中样板逻辑和代码的数量
例如,可以引入助手类型来封装线程逻辑:
class AsyncJob
{
public:
typedef boost::function<void()> fn_type;
// Start running a job asynchronously.
template <typename Fn>
AsyncJob(const Fn& fn)
: thread_(&AsyncJob::run, fn_type(fn))
{}
// Stop the job.
~AsyncJob()
{
thread_.interrupt();
// Join may throw, so catch and suppress.
try { thread_.join(); }
catch (const boost::thread_interrupted&) {}
}
private:
// into the run function so that the loop logic does not
// need to be duplicated.
static void run(fn_type fn)
{
// Continuously call the provided function until an interrupt occurs.
try
{
while (true)
{
fn();
// Force an interruption point into the loop, as the user provided
// function may never call a Boost.Thread interruption point.
boost::this_thread::interruption_point();
}
}
catch (const boost::thread_interrupted&) {}
}
boost::thread thread_;
};
另一个关键点是AsyncJob
强制将Boost.Thread引入循环逻辑。作业关闭逻辑是根据中断点实现的。因此,在迭代过程中达到中断点是至关重要的。否则,如果用户代码从未达到中断点,可能会导致死锁点
寿命
检查是线程的生存期必须与对象的生存期相关联,还是异步事件处理需要与对象的生存期相关联。如果是后者,则可能值得考虑使用线程池。线程池可以对线程资源提供更细粒度的控制,例如例如,设置一个最大限制,并尽量减少浪费线程的数量,例如线程什么都不做或创建/销毁短期线程所花费的时间
例如,考虑一个用户创建一个500代码> Dervied < /代码>类的情况。500个线程需要处理500种策略吗?或者25个线程可以处理500种策略吗?请记住,在某些系统中,线程创建/销毁可能是昂贵的,并且甚至可能存在由OS所强加的最大线程限制。
总之,检查权衡,并确定哪些行为是可接受的。将代码重构降至最低可能很困难,特别是在更改线程模型时,这会对代码库的各个领域产生影响。完美的解决方案很难获得,因此请确定涵盖大多数情况的解决方案。一旦明确定义了受支持的行为,请修改现有代码,使其处于受支持的行为中。创建一个异步处理驱动策略的队列怎么样?然后只需从队列中添加和删除这些对象即可。@mgr:事实上,我使用锁定的队列将事件推送到e strategies和processEvents方法只是从这个队列中弹出(阻塞)事件。我从示例代码中删除了这些细节,因为它不影响我主要关心的是线程生命周期。
struct Derived : public Base
{
Derived()
: job_(boost::bind(&Base::processEvents, this))
{}
virtual void processEvents()
{
// Process events in Derived specific way
}
private:
AsyncJob job_;
};