【问题标题】:C++/CX D'tor not called未调用 C++/CX D'tor
【发布时间】:2016-11-28 11:17:17
【问题描述】:

我为我们的 WinRT 应用程序创建了一个 ref class Dispatcher,它使用来自 Windows::System::Threading::ThreadPool 的线程来创建某种消息泵基础结构。必须继承Dispatcher 才能使派生类具有此机制。

问题是从这个基 Dispatcher 派生的每个类都没有被破坏(没有调用 D'tor)。

我隔离了这个问题,我想我了解导致这个问题的原因,但我不确定如何解决这个问题。

以下是一些与问题相关的代码:

public delegate void FunctionDelegate();
ref class Dispatcher
{
protected private:
    Dispatcher()
    {   
        m_invocationHandle = CreateEvent(nullptr, FALSE, FALSE, nullptr);
        m_disposed = false;

        m_asyncThread = Windows::System::Threading::ThreadPool::RunAsync(
            ref new Windows::System::Threading::WorkItemHandler(
                [this](Windows::Foundation::IAsyncAction^ operation)
        {
            while (m_disposed == false)
            {
                WaitForSingleObject(m_invocationHandle, INFINITE);
                //copy Pending Queue to Executing Queue
                //Run all handlers in Executing Queue and clear it
            }
        }));
    }

public:
    virtual ~Dispatcher()
    {
        m_disposed = true;
        SetEvent(m_invocationHandle);
        JoinInvocationThread();
        CleanUp(); //close handles etc...
    }

    void BeginInvoke(FunctionDelegate^ function)
    {
        PendingQueue->Append(function);
        SetEvent(m_invocationHandle);
    }
};

所以,由于这是一个 ref 类,它的 d'tor 应该在 ref 计数达到 0 时被调用,但是由于我将 this 传递给 WorkItemHandler 委托,线程持有对 Dispatcher 类的引用,这会导致循环引用。因此,由于线程无限等待设置m_invocationHandle 事件,因此始终存在对this 类的引用,该类永远不会调用其析构函数(应该设置m_invocationHandle 事件并等待线程完成)。

我考虑过使用Platform::WeakReference,但在调用WaitForSingleObject(...) 之前,我必须将Resolve 转换为Dispatcher^,以便获得m_invocationHandle,这无济于事,因为这会将引用计数提高为好吧。

有什么想法吗?

【问题讨论】:

  • @HansPassant 我认为您错过了 c'tor 从异步运行的线程池创建线程的事实......因此 c'tor 确实完成了
  • 分成两个对象。一种是 public Dispatcher,它引用了“真正的”调度器。当公共调度器被破坏时,它会告诉“真正的”调度器进行清理。
  • @RaymondChen,感谢您的建议,听起来很简单,并且保持了我想要的封装。我实际上通过传递对所需成员的引用而不是传递this 来解决这个问题,但你的建议听起来“更干净”

标签: c++ multithreading windows-runtime c++-cx circular-reference


【解决方案1】:

如果您不想添加“this”,请将其捕获为常规指针而不是 C++/CX 指针。只需确保您的函数在析构函数完成之前结束:

Dispatcher()
{   
    m_invocationHandle = CreateEvent(nullptr, FALSE, FALSE, nullptr);
    m_disposed = false;
    IInspectable* _this = reinterpret_cast<IInspectable*>(this);

    m_asyncThread = Windows::System::Threading::ThreadPool::RunAsync(
        ref new Windows::System::Threading::WorkItemHandler(
            [_this](Windows::Foundation::IAsyncAction^ operation)
    {
            reinterpret_cast<Dispatcher^>(_this)->MyLoop();
    }));
}

void MyLoop()
{
    while (m_disposed == false)
    {
        WaitForSingleObject(m_invocationHandle, INFINITE);
        //copy Pending Queue to Executing Queue
        //Run all handlers in Executing Queue and clear it
    }
}

【讨论】:

  • 嗯,没有。 lambda 在销毁时会释放this,现在你有一个双释放错误。
猜你喜欢
  • 2021-11-02
  • 1970-01-01
  • 2013-01-01
  • 2015-10-25
  • 1970-01-01
  • 2019-10-03
  • 2012-01-13
  • 1970-01-01
  • 2013-02-20
相关资源
最近更新 更多