C# 多執行緒程(Multithreading)【四】ThreadPool

基本概念

在 C# 中,ThreadPool 是一種高效的方式來執行背景工作或非同步任務,避免了頻繁建立與銷毀執行緒的開銷。

命名空間:

using System.Threading;

使用 ThreadPool.QueueUserWorkItem 將任務加入執行緒池:

using System;
using System.Threading;
using System.Diagnostics;//for Debug.WriteLine

class Program
{
    static void Main()
    {
        Debug.WriteLine("主執行緒開始...");

        // 將工作加入 ThreadPool
        ThreadPool.QueueUserWorkItem(WorkItem, "來自主執行緒的參數");

        Debug.WriteLine("主執行緒結束。");
    }

    static void WorkItem(object state)
    {
        Debug.WriteLine($"執行緒池工作開始,收到參數:{state}");
        Thread.Sleep(1000); // 模擬耗時工作
        Debug.WriteLine("執行緒池工作結束。");
    }
}

📌 注意事項

  • 使用者無法控制 ThreadPool 中的執行緒數量
  • 如果需要更細緻的控制,建議使用 Task 或 Thread。

  • 避免長時間運行任務
  • ThreadPool 適合用來處理短小、快速完成的工作。

  • 傳遞參數時使用 object
  • 傳遞的參數會以 object 型態處理,因此需要強制轉型。


使用 Lambda 表示式

ThreadPool.QueueUserWorkItem(state =>
{
    Console.WriteLine("執行緒池中的 Lambda 任務執行中...");
    Thread.Sleep(500);
    Console.WriteLine("任務完成");
});

在多執行緒下更新UI

不能直接在 ThreadPool 的工作執行緒中更新 UI,否則會發生錯誤(如 InvalidOperationException)。

只能在 UI 執行緒 中更新 UI 元件。

using System;
using System.Threading;
using System.Windows.Forms;

public class MainForm : Form
{
    private Button button;
    private Label label;

    public MainForm()
    {
        button = new Button { Text = "開始背景工作", Dock = DockStyle.Top };
        label = new Label { Text = "尚未開始", Dock = DockStyle.Fill, TextAlign = System.Drawing.ContentAlignment.MiddleCenter };

        button.Click += Button_Click;

        Controls.Add(label);
        Controls.Add(button);
    }

    private void Button_Click(object sender, EventArgs e)
    {
        label.Text = "背景工作進行中...";

        // 使用 ThreadPool 啟動背景工作
        ThreadPool.QueueUserWorkItem(_ =>
        {
            Thread.Sleep(2000); // 模擬耗時任務

            // 回到 UI 執行緒更新畫面
            this.Invoke((MethodInvoker)(() =>
            {
                label.Text = "背景工作完成!";
            }));
        });
    }
}

🔁 this.Invoke(...) 是什麼?

這是 WinForms 提供的方法,用來將動作「封送回 UI 執行緒」執行。對 WPF 則是使用 Dispatcher.Invoke(...)。

留言