【发布时间】: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