在许多情况下,我有类似活动对象的类(有一个线程)。为了避免访问冲突,我总是要等待析构函数的加入。这通常不是问题。
然而,假设一个版本构建带有一些错误(死锁,活锁等)导致join()
无法按时返回或根本不会返回,这会导致整个应用程序在等待对象时无法正常工作不会再使用。如果这发生在客户身上,那就成了问题。
我希望通过问题得到通知并跳过加入。泄漏线程及其资源。
通过这样的方式可以实现跳过连接。
class MyActiveObject
{
public:
MyActiveObject();
~MyActiveObject(){}
private
struct Implementation;
std::shared_ptr<Implementation> pImpl_;
};
struct MyActiveObject::Implementation : std::enable_shared_from_this<Implementation >
{
Implementation() : thread_([=]{Run();})
{
}
~Implementation()
{
#ifdef _DEBUG
thread_.join();
#else
if(!thread_.timed_join(SOME_TIMEOUT))
ALERT_SOME_HOW();
#endif
}
void Dispose()
{
isRunning_ = false;
}
void Run()
{
#ifndef _DEBUG
auto pKeepAlive = shared_from_this(); // Won't be destroyed until thread finishes
#endif
isRunning_ = true;
while(isRunning_)
{
/* ... */
}
}
boost::thread thread_;
tbb::atomic<bool> isRunning_;
};
MyActiveObject::MyActiveObject() : pImpl_(new Implementation()){}
MyActiveObject::~MyActiveObject() { pImpl_->Dispose(); }
这是个好主意吗?还是有更好的策略?
答案 0 :(得分:3)
奇怪的问题:'如果我的代码中有错误,我会遇到问题'。嗯,是。修复错误,不要试图将其打包过来。这种纸只会产生两个错误,因为在你知道第一个错误是什么之前你无法测试它。
答案 1 :(得分:1)
如果您正在编写客户端应用程序,并且在此销毁序列之后应用程序的生命周期很短,那么这似乎是一个合理的实用解决方案。我建议您添加一些日志记录并尝试收集发布日志(至少从内部测试中获取)。
如果您正在编写服务器应用程序并且在服务器关闭期间没有这种破坏,那么我会阻止这种行为,因为您的服务器经常耗尽资源不太可能是好的。
在这两种情况下,开发团队都应高度重视任何已知的死锁问题 - 即使效果对客户隐藏。
答案 2 :(得分:1)
如果可行,最好激活某种结构分析以找到循环并打破僵局。
它可能会遗漏一些关于破坏的死锁,但是它可能也适用于捕获该环境之外的死锁。