1

我爲我們的WinRT應用程序創建了ref class Dispatcher,該應用程序使用Windows::System::Threading::ThreadPool中的線程創建消息泵基礎結構。必須繼承Dispatcher才能使派生類具有此機制。C++/CX D'tor未調用

問題是從這個基本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); 
    } 
}; 

所以,因爲這是一個引用類,當裁判數爲0的D'TOR應該被調用,但因爲我通過thisWorkItemHandler委託,線程持有對Dispatcher類的引用,這會導致循環引用。因此,由於線程正在無限期地等待事件被設置,所以總是會引用一個不會調用其析構函數的類(其應該設置m_invocationHandle事件並等待線程完成)。

我想過使用Platform::WeakReference,但我必須把它ResolveDispatcher^以獲得m_invocationHandle其中,因爲這不利於將提高裁判計數以及callsing WaitForSingleObject(...)之前。

任何想法?

+0

@HansPassant我想你錯過了c'tor創建從異步運行的線程池中的線程......這樣的C事實'tor完成 – ZivS

+0

分成兩個對象。一個是公共調度員,它提到了「真正的」調度員。當公共調度員被破壞時,它會告訴「真正的」調度員進行清理。 –

+0

@RaymondChen,感謝您的建議,聽起來很簡單,並保持我想要的封裝。我實際上是通過給所需成員傳遞引用來解決這個問題,而不是傳遞'this',但是你的建議聽起來更「乾淨」 – ZivS

回答

0

如果您不想添加,請將「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 
    } 
} 
+1

嗯,不。 lambda在破壞時會釋放'this',現在你有一個雙重的錯誤。 –

+0

你說得對。固定。 – Sunius