首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

.NET 客戶端應用程式多執行緒實戰:ThreadPool、Invoke 模式、取消機制與 Timer 選擇

     編輯:關於.NET

為何客戶端需要多執行緒

單一執行緒 GUI 程式中,長時間運算 (資料庫查詢、複雜計算) 會阻塞訊息迴圈,導致介面凍結:無法點擊、輸入、重繪、關閉視窗。解決方案:**UI 執行緒專責訊息泵,背景執行緒處理耗時工作**。

單一執行緒凍結示範

void OnClick(object sender, EventArgs e)
{
    int seconds = int.Parse(textBox.Text);
    for (int i = 0; i < seconds; i++)
    {
        Interaction.Beep();
        Thread.Sleep(1000);
    }
}

介面凍結截圖

輸入 20 秒,介面完全無回應 20 秒 (無法移動、重繪、關閉)。

Windows Forms 訊息架構

  • 建立於 User32 Win32 API 之上
  • 視窗程序 WndProc 處理訊息
  • 應用程式必須主動 GetMessage / DispatchMessage (訊息泵)
  • Application.Run() 封裝訊息泵,主執行緒終身阻塞於此
  • 事件處理器 (如 OnClick) 在 **同一主執行緒** 執行

長時間運算佔用主執行緒 → 訊息泵停止 → 介面凍結。

ThreadPool 解決介面凍結

void OnClick(object sender, EventArgs e)
{
    int seconds = int.Parse(textBox.Text);
    WaitCallback work = new WaitCallback(Count);
    ThreadPool.QueueUserWorkItem(work, seconds);
}

void Count(object param)
{
    int seconds = (int)param;
    for (int i = 0; i < seconds; i++)
    {
        Interaction.Beep();
        Thread.Sleep(1000);
    }
}

ThreadPool.QueueUserWorkItem 將工作排入佇列,CLR 執行緒池執行,主執行緒立即返回處理訊息。**介面保持回應**。

新問題:重複觸發並發衝突

使用者可連續點擊按鈕啟動多個背景工作,造成資源爭用或資料損毀。

最簡單的同步:停用 UI 控制項

delegate void BoolCallback(bool enable);
BoolCallback _enableControls;

public Form1()
{
    // ...
    _enableControls = new BoolCallback(EnableControls);
}

void OnClick(object sender, EventArgs e)
{
    EnableControls(false);           // 立即停用
    ThreadPool.QueueUserWorkItem(Count, seconds);
}

void Count(object param)
{
    // ... 背景工作 ...
    Invoke(_enableControls, new object[] { true }); // 完成後啟用
}

void EnableControls(bool enable)
{
    button.Enabled = enable;
    textBox.Enabled = enable;
}
  • Control.Invoke:將委派排入 **UI 執行緒** 執行佇列,**唯一可從任何執行緒安全呼叫的控制項方法** (內部用 PostMessage)
  • 背景執行緒**絕不可**直接存取控制項屬性/方法

實作取消功能:AutoResetEvent

AutoResetEvent:兩狀態 (有訊號/無訊號) 執行緒同步基元。

實作步驟

  1. 表單建立 AutoResetEvent _cancelEvent = new AutoResetEvent(false)
  2. 加入「取消」按鈕,Click 事件呼叫 _cancelEvent.Set()
  3. 背景工作週期性檢查:
if (_cancelEvent.WaitOne(0, false)) // 0 毫秒逾時,非阻塞檢查
{
    // 執行取消邏輯
    return;
}
  • WaitOne(0) 立即返回:true = 有訊號 (使用者取消),false = 逾時 (未取消)
  • 偵測到訊號後自動重置為無訊號狀態

偽取消模式

若背景作業不可真正取消 (如 DataAdapter.Fill),可採用偽取消:

  • 取消按鈕直接啟用 UI 控制項
  • 背景工作完成時檢查取消旗標,忽略結果
  • 適用:查詢操作;不適用:更新/刪除/插入、聲音/影像等有永久副作用操作

Timer 選擇:System.Windows.Forms.Timer vs System.Threading.Timer

特性System.Windows.Forms.TimerSystem.Threading.Timer
執行緒UI 執行緒 (WM_TIMER 訊息)ThreadPool 執行緒
同步需求無需 Invoke/同步機制
精確度~55ms (訊息迴圈)較高
適用場景UI 週期性更新 (時鐘、狀態列)非 UI 背景週期性工作

原則: Windows Forms 專案**優先使用 System.Windows.Forms.Timer**,除非明確需要 ThreadPool 回呼。

展望:Avalon (WPF) 的 UIContext

下一代 UI 架構中,每個 UI 元素關聯邏輯執行緒上下文 (UIContext),提供 Invoke/BeginInvoke,邏輯與 WinForms Control.Invoke 一致。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved