HOW TO:建立和結束執行緒 (C# 程式設計手冊)

更新:2007 年 11 月

此範例示範如何建立輔助執行緒或背景工作執行緒,以及使用它們和主要執行緒同時執行處理過程。同時也示範讓一個執行緒等候另一個執行緒,以及順利地結束執行緒。如需多執行緒處理的背景資訊,請參閱 Managed 執行緒使用執行緒 (C# 程式設計手冊)

這個範例會建立名為 Worker 的類別 (Class),其中包含背景工作執行緒 (Worker Thread) 將會執行的 DoWork 方法。在本質上,這是背景工作執行緒的 Main 函式。背景工作執行緒將會呼叫這個方法以開始執行,當此方法傳回時便會自動結束。DoWork 方法看起來會像這樣:

public void DoWork()
{
    while (!_shouldStop)
    {
        Console.WriteLine("worker thread: working...");
    }
    Console.WriteLine("worker thread: terminating gracefully.");
}

Worker 類別包含額外的方法,此方法用來表示它應該傳回的 DoWork。這個方法稱為 RequestStop,看起來像這樣:

public void RequestStop()
{
    _shouldStop = true;
}

RequestStop 方法只會將 _shouldStop 資料成員指派給 true。因為這個資料成員是由 DoWork 方法檢查,這樣便會有導致 DoWork 傳回的間接效果,並且進而結束了背景工作執行緒。然而,您應該注意到 DoWork 和 RequestStop 將會由不同的執行緒所執行。DoWork 是由背景工作執行緒執行,RequestStop 則是由主執行緒 (Primary Thread) 執行,所以 _shouldStop 資料成員會宣告為 volatile,如下所示:

private volatile bool _shouldStop;

volatile 關鍵字會警示多執行緒將存取 _shouldStop 資料成員的編譯器,因此對於此成員的狀態不應做出最佳化假設。如需詳細資訊,請參閱 volatile (C# 參考)

搭配 _shouldStop 資料成員使用 volatile 可讓您安全地從多執行緒存取這個成員,而不需要使用正式的執行緒同步處理技術,這只因為 _shouldStop 是 bool。這表示只有單一而不可部分完成的作業 (Atomic Operation) 需要修改 _shouldStop。然而,如果此資料成員是類別、結構 (Struct) 或陣列,則從多執行緒存取它可能會導致不穩定的資料毀損。請考慮會變更陣列中之值的執行緒。Windows 會定期中斷執行緒以允許其他執行緒執行。因此,這個執行緒可能會在指派一些陣列元素之後、以及在指派其他元素之前停止。因為現在陣列處於程式設計人員未意料到的狀態,所以讀取此陣列的另一個執行緒可能會失敗。

在真正建立背景工作執行緒之前,Main 函式會建立 Worker 物件和 Thread 的執行個體。將 Worker.DoWork 方法的參考傳遞至 Thread 建構函式,可讓執行緒物件設定為使用此方法做為進入點,如下所示:

Worker workerObject = new Worker();
Thread workerThread = new Thread(workerObject.DoWork);

此時,雖然已有背景工作執行緒物件並已設定完成,但尚未建立真正的背景工作執行緒。直到 Main 呼叫 Start 方法,才會建立這個背景工作執行緒。

workerThread.Start();

這時系統會初始化背景工作執行緒的執行,但它的動作卻與主要執行緒非同步。這意味著,Main 函式會馬上繼續執行程式碼,而背景工作執行緒會同時進行初始化。為了確定 Main 函式不會嘗試在背景工作執行緒有機會執行之前將其結束,Main 函式會重複執行,直到背景工作執行緒物件的 IsAlive 屬性設定為 true:

while (!workerThread.IsAlive);

接著,會以 Sleep 的呼叫短暫停止主執行緒。這樣便能確保背景工作執行緒的 DoWork 函式將會在 Main 函式執行更多命令之前,在 DoWork 方法的內部多次反覆執行:

Thread.Sleep(1);

在經過 1 毫秒之後,Main 就會對背景工作執行緒物件發出信號,表示該物件應該使用先前所介紹的 Worker.RequestStop 方法來結束:

workerObject.RequestStop();

這時也可以透過呼叫 Abort,從另一個執行緒來結束執行緒。這樣便會強制結束即使尚未完成工作的受影響執行緒,而且不會提供清除資源的機會。此範例中所示範的技術是較偏好的做法。

最後,Main 函式會呼叫背景工作執行緒物件上的 Join 方法。此方法會造成目前的執行緒封鎖或等候,直到物件所代表的執行緒結束為止。因此,不會傳回 Join,直到背景工作執行緒傳回為止並藉此自行結束:

workerThread.Join();

目前只有執行 Main 的主要執行緒存在。它會顯示一個最後訊息,然後傳回,並同時結束主執行緒。

以下是完整的範例。

範例

using System;
using System.Threading;

public class Worker
{
    // This method will be called when the thread is started.
    public void DoWork()
    {
        while (!_shouldStop)
        {
            Console.WriteLine("worker thread: working...");
        }
        Console.WriteLine("worker thread: terminating gracefully.");
    }
    public void RequestStop()
    {
        _shouldStop = true;
    }
    // Volatile is used as hint to the compiler that this data
    // member will be accessed by multiple threads.
    private volatile bool _shouldStop;
}

public class WorkerThreadExample
{
    static void Main()
    {
        // Create the thread object. This does not start the thread.
        Worker workerObject = new Worker();
        Thread workerThread = new Thread(workerObject.DoWork);

        // Start the worker thread.
        workerThread.Start();
        Console.WriteLine("main thread: Starting worker thread...");

        // Loop until worker thread activates.
        while (!workerThread.IsAlive);

        // Put the main thread to sleep for 1 millisecond to
        // allow the worker thread to do some work:
        Thread.Sleep(1);

        // Request that the worker thread stop itself:
        workerObject.RequestStop();

        // Use the Join method to block the current thread 
        // until the object's thread terminates.
        workerThread.Join();
        Console.WriteLine("main thread: Worker thread has terminated.");
    }
}

輸出如下:

main thread: starting worker thread...
worker thread: working...
worker thread: working...
worker thread: working...
worker thread: working...
worker thread: working...
worker thread: working...
worker thread: working...
worker thread: working...
worker thread: working...
worker thread: working...
worker thread: working...
worker thread: terminating gracefully...
main thread: worker thread has terminated

請參閱

工作

執行緒處理範例

概念

C# 程式設計手冊

參考

執行緒 (C# 程式設計手冊)

使用執行緒 (C# 程式設計手冊)

Thread

volatile (C# 參考)

Mutex

Monitor

Start

IsAlive

Sleep

Join

Abort

其他資源

Managed 執行緒

執行緒範例