Я создал ref class Dispatcher
для нашего приложения WinRT, которое использует поток из 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 должен вызываться, когда счетчик ссылок достигает 0, но так как я передаю this
к WorkItemHandler
делегат, поток содержит ссылку на Dispatcher
класс, который вызывает циклическую ссылку. Таким образом, поскольку поток бесконечно ждет m_invocationHandle
событие, которое будет установлено, всегда есть ссылка на this
класс, который никогда не будет вызывать свой деструктор (который должен установить m_invocationHandle
событие и ждать завершения потока).
Я думал об использовании Platform::WeakReference
но мне придется Resolve
это к Dispatcher^
перед звонком WaitForSingleObject(...)
для того, чтобы получить m_invocationHandle
что не помогает, так как это также увеличит количество ссылок.
Есть идеи?
Захватывайте «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
}
}
Других решений пока нет …