gpt4 book ai didi

c++ - 在派生类中管理线程生命周期

转载 作者:太空宇宙 更新时间:2023-11-04 14:11:09 25 4
gpt4 key购买 nike

我有一个 Base 类,它充当多个同步事件处理策略的接口(interface)。我现在想要策略异步处理事件。为了最小化代码重构,每个策略都有自己的内部线程用于异步事件处理。我主要关心的是如何管理这个线程的生命周期。 Derived 策略类是围绕代码库构建和销毁的,因此很难在策略类之外管理线程生命周期(启动/停止)。

我最终得到了以下代码:

#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;
}

如您所见,线程在Derived 类析构函数中被中断并加入。 Stackoverflow 上的许多评论认为在析构函数中加入线程是个坏主意。但是,考虑到线程生命周期必须通过 Derived 类的构造/析构来管理的约束,我找不到更好的主意。有人有更好的建议吗?

最佳答案

在类被销毁时释放类创建的资源是个好主意,即使其中一个资源是线程。但是,在析构函数中执行任何重要任务时,通常值得花时间全面检查其含义。


析构函数

一般规则是 not throw exceptions in destructors .如果 Derived 对象位于从另一个异常展开的堆栈上,并且 Derived::~Derived() 抛出异常,则 std::terminate( ) 将被调用,终止应用程序。虽然 Derived::~Derived() 没有显式抛出异常,但重要的是要考虑它调用的某些函数可能会抛出异常,例如 _thread->join() .

如果 std::terminate() 是所需的行为,则无需更改。但是,如果不需要 std::terminate(),则捕获 boost::thread_interrupted 并抑制它。

try
{
_thread->join();
}
catch (const boost::thread_interrupted&)
{
/* suppressed */
}

继承

看起来好像继承被用于代码重用和通过将异步行为隔离到 Base 层次结构内部来最小化代码重构。但是,一些样板逻辑也在 Dervied 中。由于必须更改从 Base 派生的类,我建议考虑聚合或 CRTP以尽量减少这些类中的样板逻辑和代码量。

例如可以引入helper类型来封装线程逻辑:

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_;
};

这个辅助类可以在 Derived 的构造函数中聚合和初始化。它消除了对大部分样板代码的需要,并且可以在其他地方重复使用:

struct Derived : public Base
{
Derived()
: job_(boost::bind(&Base::processEvents, this))
{}

virtual void processEvents()
{
// Process events in Derived specific way
}

private:

AsyncJob job_;
};

另一个关键点是 AsyncJob 强制执行 Boost.Thread interruption point进入循环逻辑。作业关闭逻辑是根据中断点来实现的。因此,在迭代期间达到中断点至关重要。否则,如果用户代码从未到达中断点,则可能会陷入死锁。


生命周期

检查是否是线程的生命周期必须与对象的生命周期相关联,或者是否是异步事件处理需要与对象的生命周期相关联。如果是后者,那么可能值得考虑使用线程池。线程池可以对线程资源提供更细粒度的控制,例如施加最大限制,并最大限度地减少浪费的线程数量,例如什么都不做的线程或花费时间创建/销毁短期线程。

例如,考虑用户创建一个包含 500 个 Dervied 类的数组的情况。是否需要 500 个线程来处理 500 个策略?还是 25 个线程可以处理 500 个策略?请记住,在某些系统上,线程的创建/销毁可能代价高昂,操作系统甚至可能会施加最大线程限制。


最后,检查权衡,并确定哪些行为是可以接受的。将代码重构最小化可能很困难,尤其是在更改对代码库的各个区域有影响的线程模型时。完美的解决方案很难获得,因此请确定涵盖大多数情况的解决方案。明确定义支持的行为后,着手修改现有代码,使其在支持的行为范围内。

关于c++ - 在派生类中管理线程生命周期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14218720/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com