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

C# 多線程程式設計入門:WinForms 線程控制實戰

     編輯:關於C語言

前言

多線程是 C# 開發的核心技能。本文透過一個完整的 WinForms 範例,展示如何建立、啟動、暫停與安全終止背景線程,並正確處理跨線程 UI 更新——這是初學者最容易踩坑的地方。

專案架構

  • 一個 TextBox:輸入計數上限
  • 一個 Label:顯示即時計數進度
  • 三個 Button:啟動、停止、關閉

核心代碼解析

1. 線程與同步物件宣告

public partial class ThreadDemoForm : Form
{
    private Thread _workerThread;
    private int _maxCount;
    private int _currentIndex = 0;
    private readonly object _lockObj = new object();
    
    public ThreadDemoForm() => InitializeComponent();

2. 背景線程執行邏輯

private void WorkerThreadProc()
{
    try
    {
        while (true)
        {
            // 檢查是否需重置計數
            if (_currentIndex >= _maxCount)
                _currentIndex = 0;

            // 關鍵:跨線程更新 UI 必須透過 Invoke/BeginInvoke
            this.BeginInvoke(new Action(() => 
            {
                lblResult.Text = $"{_currentIndex} / {_maxCount}";
            }));

            _currentIndex++;
            Thread.Sleep(50); // 模擬工作負載
        }
    }
    catch (ThreadInterruptedException)
    {
        // 線程被中斷時的優雅退出
    }
    finally
    {
        // 清理資源
    }
}

3. 線程生命週期控制

private void StartThread()
{
    StopThread(); // 確保舊線程已停止
    
    _maxCount = int.Parse(txtCount.Text);
    _currentIndex = 0;
    
    _workerThread = new Thread(WorkerThreadProc)
    {
        IsBackground = true // 設為背景線程,主視窗關閉時自動結束
    };
    _workerThread.Start();
}

private void StopThread()
{
    if (_workerThread != null && _workerThread.IsAlive)
    {
        _workerThread.Interrupt(); // 發送中斷信號
        _workerThread.Join(1000);  // 等待線程結束(最多 1 秒)
        _workerThread = null;
    }
}

4. 事件處理器

private void btnStart_Click(object sender, EventArgs e)
{
    if (int.TryParse(txtCount.Text, out int count) && count > 0)
        StartThread();
}

private void btnStop_Click(object sender, EventArgs e) => StopThread();

private void btnClose_Click(object sender, EventArgs e)
{
    StopThread();
    this.Close();
}

關鍵概念深度解析

為什麼要用 BeginInvoke?

Windows Forms 控制項具有線程親和性,只能在建立它們的 UI 線程中存取。背景線程直接存取 lblResult.Text 會拋出 InvalidOperationException。BeginInvoke 將委派排入 UI 線程訊息佇列非同步執行,不阻塞背景線程。

Thread.Interrupt vs Thread.Abort

方法行為推薦度
Interrupt喚醒等待中的線程,拋出 ThreadInterruptedException,允許 finally 區塊執行✅ 推薦
Abort強制終止,可能導致資料損壞、鎖定未釋放,.NET Core 已移除❌ 棄用
CancellationToken現代協作式取消模式,配合 ThrowIfCancellationRequested✅ 最佳實踐

現代化改寫建議(.NET 4.5+)

private CancellationTokenSource _cts;

private async void btnStart_Click(object sender, EventArgs e)
{
    _cts = new CancellationTokenSource();
    int max = int.Parse(txtCount.Text);
    
    try 
    {
        for (int i = 0; !_cts.Token.IsCancellationRequested; i = (i + 1) % max)
        {
            lblResult.Text = $"{i} / {max}";
            await Task.Delay(50, _cts.Token);
        }
    }
    catch (OperationCanceledException) { /* 正常取消 */ }
}

private void btnStop_Click(object sender, EventArgs e) => _cts?.Cancel();

總結

掌握線程建立、跨線程 UI 更新、優雅停止機制是多線程開發的基石。現代專案請優先採用 Task / async-await / CancellationToken 模式,程式碼更簡潔、除錯更容易、且避免傳統線程的常見陷阱。

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