C++ C++/CX D';tor未呼叫
我为我们的WinRT应用程序创建了一个C++ C++/CX D';tor未呼叫,c++,multithreading,windows-runtime,c++-cx,circular-reference,C++,Multithreading,Windows Runtime,C++ Cx,Circular Reference,我为我们的WinRT应用程序创建了一个ref类调度程序,它使用Windows::System::Threading::ThreadPool中的一个线程来创建某种消息泵基础结构。必须继承调度程序,才能使派生类具有此机制 问题是,从这个基本调度器派生的每个类都没有被破坏(没有调用D'tor) 我隔离了这个问题,我想我已经了解了这个问题的原因,但我不确定如何解决这个问题 以下是与此问题相关的一些代码: public delegate void FunctionDelegate(); ref class
ref类调度程序
,它使用Windows::System::Threading::ThreadPool
中的一个线程来创建某种消息泵基础结构。必须继承调度程序
,才能使派生类具有此机制
问题是,从这个基本调度器派生的每个类都没有被破坏(没有调用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类,当ref计数达到0时应该调用它的d'tor,但由于我将this
传递给WorkItemHandler
委托,因此线程持有对Dispatcher
类的引用,这会导致循环引用。因此,由于线程无限期地等待m_invocationHandle
事件的设置,因此始终存在对this
类的引用,该类永远不会调用其析构函数(该类应设置m_invocationHandle
事件并等待线程完成)
我曾考虑过使用Platform::WeakReference
,但在调用WaitForSingleObject(…)
之前,我必须将其解析为Dispatcher^
,以获得m\u调用句柄,这也会增加ref计数,因此毫无帮助
有什么想法吗?如果不想添加“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
}
}
Dispatcher()
{
m_invocationHandle=CreateEvent(nullptr,FALSE,FALSE,nullptr);
m_=false;
IInspectable*_this=重新解释铸件(this);
m_asyncThread=Windows::System::Threading::ThreadPool::RunAsync(
ref新Windows::System::Threading::WorkItemHandler(
[_this](Windows::Foundation::IAsyncation^操作)
{
重新解释cast(_this)->MyLoop();
}));
}
void MyLoop()
{
while(m_=false)
{
WaitForSingleObject(m_调用句柄,无限);
//将挂起队列复制到执行队列
//运行执行队列中的所有处理程序并将其清除
}
}
如果不希望添加“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
}
}
Dispatcher()
{
m_invocationHandle=CreateEvent(nullptr,FALSE,FALSE,nullptr);
m_=false;
IInspectable*_this=重新解释铸件(this);
m_asyncThread=Windows::System::Threading::ThreadPool::RunAsync(
ref新Windows::System::Threading::WorkItemHandler(
[_this](Windows::Foundation::IAsyncation^操作)
{
重新解释cast(_this)->MyLoop();
}));
}
void MyLoop()
{
while(m_=false)
{
WaitForSingleObject(m_调用句柄,无限);
//将挂起队列复制到执行队列
//运行执行队列中的所有处理程序并将其清除
}
}
@HansPassant我认为您忽略了这样一个事实,即c'tor从异步运行的线程池中创建了一个线程……因此c'tor确实完全分解为两个对象。一个是公共调度器,它引用了“真实”的调度器。当公共调度器被破坏时,它会告诉“真正的”调度器清理。@RaymondChen,谢谢你的建议,听起来很简单,并保留了我想要的封装。实际上,我通过将引用传递给所需的成员而不是传递this
,解决了这个问题,但是您的建议听起来“更干净”@HansPassant我认为您忽略了这样一个事实,即c'tor从线程池创建了一个线程,该线程池异步运行……因此c'tor确实完全拆分为两个对象。一个是公共调度器,它引用了“真实”的调度器。当公共调度器被破坏时,它会告诉“真正的”调度器清理。@RaymondChen,谢谢你的建议,听起来很简单,并保留了我想要的封装。实际上,我通过将引用传递给所需的成员而不是传递this
,解决了这个问题,但是你的建议听起来“更干净”嗯,不。lambda在破坏时会释放this
,现在你有了一个双释放bug。嗯,不。lambda在破坏时会释放this
,现在你有了一个双重版本的bug。