0

在许多情况下,我的类就像活动对象(有一个线程)。并且为了避免访问冲突,我总是必须等待加入析构函数。这通常不是问题。

然而,想象一个带有一些错误(死锁、活锁等)的发布版本会导致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(); }

这是一个好主意吗?还是有更好的策略?

4

3 回答 3

3

奇怪的问题:'如果我的代码中有错误,我就有问题'。嗯,是。修复错误,不要试图将其覆盖。这种论文只会产生两个错误,因为在您知道第一个错误是什么之前,您无法对其进行测试。

于 2010-09-08T16:51:42.543 回答
1

如果您正在编写客户端应用程序并且在此销毁序列之后应用程序的生命周期很短,那么这似乎是一个合理的实用解决方案。我鼓励您添加一些日志记录并尝试收集发布日志(至少来自您的内部测试)。

如果您正在编写服务器应用程序并且这种破坏不是在服务器关闭期间,那么我会阻止这种行为,因为您的服务器经常耗尽资源不太可能是好的。

在这两种情况下,任何已知的死锁问题都应该由开发团队以高优先级来处理——即使对客户隐藏了影响。

于 2010-09-08T16:45:12.843 回答
1

如果可行,最好激活某种结构分析来找到循环并打破僵局。

它可能会错过一些破坏时的死锁,但它也可能适用于捕获该上下文之外的死锁。

于 2010-09-08T16:46:35.980 回答