1

Я создал ref class Dispatcher для нашего приложения WinRT, которое использует поток от Windows::System::Threading::ThreadPool для создания своего рода инфраструктуры сообщений. Dispatcher должен быть унаследован для того, чтобы производный класс имел этот механизм.C++/CX D'tor не называется

Проблема в том, что каждый класс, полученный из этой базы Диспетчер, не разрушается (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); 
    } 
}; 

Так, так как это класс исх его d'тор должен быть вызван, когда счетчик ссылок достигает 0, но так как я прохожу this к делегат WorkItemHandler, поток содержит ссылку на класс Dispatcher, который вызывает круговую ссылку. Таким образом, поскольку поток бесконечно ждет события m_invocationHandle, которое всегда задается, всегда ссылается на класс this, который никогда не вызовет его деструктор (который должен установить событие m_invocationHandle и ждать завершения потока).

Я думал об использовании Platform::WeakReference, но я должен буду Resolve его к Dispatcher^ перед тем callsing WaitForSingleObject(...) для того, чтобы получить m_invocationHandle, который не помогает, так как это повысит кол-реф, а также.

Любые идеи?

+0

@HansPassant Я думаю, вы пропустили тот факт, что c'tor создает поток из пула потоков, который работает асинхронно ... таким образом, гр 'tor завершает – ZivS

+0

Разделить на два объекта. Один из них - публичный диспетчер, который имеет ссылку на «реального» диспетчера. Когда общественный диспетчер разрушен, он сообщает «реальному» диспетчеру очистить. –

+0

@ RaymondChen, спасибо за предложение, звучит просто и поддерживает инкапсуляцию, которую я хотел. Я на самом деле решил это, передав ссылки на требуемые члены вместо того, чтобы передавать 'this', но ваши предложения звучат« чище » – ZivS

ответ

0

Захватите «это» как обычный указатель, а не указатель 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 
    } 
} 
+1

Um, no. Лямбда выпустит «это», когда он разрушит, и теперь у вас есть ошибка с двойной ошибкой. –

+0

Вы правы. Исправлена. – Sunius

Смежные вопросы