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

C# 多執行緒同步範例:Monitor、事件通知與安全停止執行緒

     編輯:C# 入門

前言

多執行緒共同存取共享資料時,必須同步化避免競爭條件。本文以「兩條執行緒共同從 ArrayList 移除元素」為例,示範 Monitor 鎖定、Event 通知完成、Thread.Abort 停止 (含現代替代方案) 的完整流程。

核心類別設計


using System;
using System.Collections;
using System.Threading;

public class ThreadSyncDemo
{
    private Thread _thread1;
    private Thread _thread2;
    private ArrayList _sharedList;
    private event EventHandler _onCompleted; // 完成事件

    public ThreadSyncDemo(int itemCount)
    {
        // 初始化資料
        _sharedList = new ArrayList(itemCount);
        var rnd = new Random(1000000);
        for (int i = 0; i < itemCount; i++)
            _sharedList.Add(rnd.Next().ToString());

        _thread1 = new Thread(Worker) { Name = "執行緒-1" };
        _thread2 = new Thread(Worker) { Name = "執行緒-2" };

        _onCompleted += OnCompletedHandler;
    }

    public void Start()
    {
        _thread1.Start();
        _thread2.Start();
    }

    private void Worker()
    {
        string item = null;
        while (true)
        {
            Monitor.Enter(this); // 進入關鍵區段
            try
            {
                if (_sharedList.Count == 0) break; // 雙重檢查

                item = (string)_sharedList[0];
                Console.WriteLine($"{Thread.CurrentThread.Name} 移除: {item}");
                _sharedList.RemoveAt(0);

                if (_sharedList.Count == 0)
                    _onCompleted?.Invoke(this, EventArgs.Empty); // 觸發完成事件
            }
            finally
            {
                Monitor.Exit(this); // 確保釋放鎖
            }

            Thread.Sleep(5); // 模擬處理延遲
        }
    }

    private void OnCompletedHandler(object sender, EventArgs e)
    {
        Console.WriteLine("所有項目處理完成,停止所有執行緒。");
        // 注意:Abort 已過時,現代做法見下方
        _thread2.Abort();
        _thread1.Abort();
    }
}

// 使用
class Program
{
    static void Main()
    {
        var demo = new ThreadSyncDemo(1000);
        demo.Start();
        Console.ReadLine();
    }
}

關鍵點解析

1. Monitor.Enter/Exit — 互斥鎖

  • Monitor.Enter(this) 以目前實例為鎖物件,確保同一時間只有一條執行緒執行關鍵區段。
  • **必須在 finally 中呼叫 Monitor.Exit**,否則例外導致鎖永不釋放造成死結。
  • 等同 lock (this) { ... },但 Monitor 可搭配 TryEnter(timeout) 避免永久阻塞。

2. 事件通知完成


_onCompleted += OnCompletedHandler; // 訂閱
_onCompleted?.Invoke(this, EventArgs.Empty); // 發布 (C# 6+ null 條件運算子)
  • 事件封裝多播委派,外部只能 +=/-=,符合封裝原則。
  • 完成時觸發事件,主執行緒或其他元件可訂閱處理後續邏輯 (如更新 UI、釋放資源)。

3. Thread.Abort 缺點與現代替代

Thread.Abort 會在目標執行緒擲出 ThreadAbortException,導致:

  • 無法預測中斷點,可能破壞不變量 (如檔案寫入一半、鎖未釋放)。
  • .NET Core / .NET 5+ **不支援**,呼叫會擲 PlatformNotSupportedException。

現代取消模式:CancellationToken


public class ModernThreadSyncDemo
{
    private CancellationTokenSource _cts = new CancellationTokenSource();
    private List _sharedList = new List();
    private readonly object _lock = new object();

    public void Start(int count)
    {
        // 初始化資料...
        var t1 = Task.Run(() => Worker("Worker-1"), _cts.Token);
        var t2 = Task.Run(() => Worker("Worker-2"), _cts.Token);
        // 可選:等待完成
        Task.WhenAll(t1, t2).ContinueWith(_ => Console.WriteLine("全部完成"));
    }

    private void Worker(string name)
    {
        while (true)
        {
            string item = null;
            lock (_lock)
            {
                if (_sharedList.Count == 0) break;
                item = _sharedList[0];
                _sharedList.RemoveAt(0);
            }

            // 模擬工作
            Thread.Sleep(5);

            // 定期檢查取消
            if (_cts.Token.IsCancellationRequested) break;
        }
    }

    public void Cancel() => _cts.Cancel();
}
  • CancellationToken 協作式取消,執行緒自行檢查並優雅結束。
  • 搭配 Task/Task.Run,無需手動管理 Thread 物件。
  • ThrowIfCancellationRequested 可在等待點 (如 Task.Delay) 直接拋出 OperationCanceledException。

進階同步原語比較

原語用途關鍵方法
lock / Monitor互斥存取關鍵區段Enter/Exit, TryEnter
Mutex跨進程同步WaitOne, ReleaseMutex
Semaphore/Slim限制並發數量Wait, Release
AutoResetEvent單一執行緒通知Set, WaitOne
ManualResetEvent/Slim廣播通知多執行緒Set, Reset, WaitOne
CountdownEvent等待 N 個信號Signal, Wait
Barrier多執行緒同步點SignalAndWait
ReaderWriterLockSlim讀多寫少優化EnterReadLock, EnterWriteLock
Interlocked原子操作 (計數、交換)Increment, CompareExchange

總結

  • 共享資料存取**必須加鎖** (lock/Monitor),並用 finally 確保釋放。
  • 任務完成通知用**事件**或 TaskCompletionSource,避免輪詢。
  • **停止執行緒請用 CancellationToken 協作式取消**,拒絕 Thread.Abort。
  • 新專案優先使用 Task/async-await、System.Threading.Channels、BlockingCollection 等高階抽象,減少手動同步複雜度。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved