簡體   English   中英

Windows窗體:是否有一種方法可以等待對控件的所有未決調用結束?

[英]Windows Forms: Is there a way to wait for all pending Invokes to a Control to end?

我需要這樣做以解決僵局。 我的Windows窗體控件有對C ++ / CLI類的引用,該類包裝了C ++本機類。 本機類對C ++ / CLI類進行回調,該回調將它們映射到表單處理的事件。 從始終運行的線程中調用這些回調。

當我想處置控件時,我注銷所有事件,以使本機類不再能回調。 完成此操作后,我將處置C ++ / CLI包裝器,這反過來會破壞本機類。 在本機類析構函數中,我使用Windows事件通知線程結束,並無限期地等待線程結束。

但是,如果在處置開始時線程位於回調的中間,則可能在Control.Invoke中將其停止,並隨后發生死鎖。 因此,標題問題。 這可能嗎? 如果是這樣,我可以這樣進行:

  • 取消注冊所有事件(本地線程將無法再回調)
  • 等待所有待處理的調用完成
  • 處置C ++ / CLI包裝器
    • 銷毀C ++本機類
      • 信號線程結束
      • 等待線程結束(由於所有Invoke均已完成,因此無法用Invoke造成死鎖,並且由於未注冊事件而無法解雇它們)

我願意接受其他解決此問題的建議

選項1:在刪除事件處理程序之后但在析構函數之前,通過Application.DoEvents處理掛起的回調。 請注意,文檔說這可以處理Windows消息,並且沒有提及是否強制處理調用。

選項2:不阻止事件線程:通過BeginInvoke調用表單回調。 請注意,在C ++對象被銷毀后,您可能會得到事件,因此,請向事件處理程序中添加其他邏輯,以確保C ++對象未被銷毀。

FYI, BeginInvokeInvoke都使用此功能。 BeginInvokesynchronous設置為false。 請注意,我稍微修改了此方法以刪除不感興趣的部分:

private object MarshaledInvoke(Control caller, Delegate method, object[] args, bool synchronous)
{
    ThreadMethodEntry entry = new ThreadMethodEntry(caller, method, args, synchronous, executionContext);
    lock (this.threadCallbackList)
    {
        if (threadCallbackMessage == 0)
            threadCallbackMessage = SafeNativeMethods.RegisterWindowMessage(Application.WindowMessagesVersion + "_ThreadCallbackMessage");
        this.threadCallbackList.Enqueue(entry);
    }
    UnsafeNativeMethods.PostMessage(new HandleRef(this, this.Handle), threadCallbackMessage, IntPtr.Zero, IntPtr.Zero);

    // BeginInvoke just takes this branch instead of waiting for completion
    if (!synchronous)
        return entry;
    if (!entry.IsCompleted)
        this.WaitForWaitHandle(entry.AsyncWaitHandle);
    if (entry.exception != null)
        throw entry.exception;
    return entry.retVal;
}

沒有可能響應表單關閉事件並等待線程完成。 有一個無法解決的線程競爭條件。 死鎖的可能性非常高,DoEvents可以打破死鎖,但是太丑陋了。

實現FormClosing事件,並告訴類停止運行其線程。 取消關閉 線程應該在退出之前引發一個事件。 在事件處理程序中使用BeginInvoke()封送對主線程的調用。

現在,您可以保證所有調用均已完成,因為它們是有序的。 此外,您可以保證線程不再生成任何事件,因此不再有調用發生,並且取消訂閱事件是安全的(實際上不是必需的)。 設置一個標志,表明現在可以進行真正的關閉,並調用Close()來實際上關閉窗體。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM