C#線程處理演示代碼

wen5 10年前發布 | 2K 次閱讀 C#

本示例演示了下面的線程處理技術。
創建、啟動和終止線程
使用線程池
線程同步和互交 ThreadPool.cs

using System;
using System.Threading;

// Fibonacci 類為使用輔助
// 線程執行長時間的 Fibonacci(N) 計算提供了一個接口。
// N 是為 Fibonacci 構造函數提供的,此外還提供了
// 操作完成時對象發出的事件信號。
// 然后,可以使用 FibOfN 屬性來檢索結果。
public class Fibonacci
{
    public Fibonacci(int n, ManualResetEvent doneEvent)
    {
        _n = n;
        _doneEvent = doneEvent;
    }

    // 供線程池使用的包裝方法。
    public void ThreadPoolCallback(Object threadContext)
    {
        int threadIndex = (int)threadContext;
        Console.WriteLine("thread {0} started...", threadIndex);
        _fibOfN = Calculate(_n);
        Console.WriteLine("thread {0} result calculated...", threadIndex);
        _doneEvent.Set();
    }

    // 計算第 N 個斐波納契數的遞歸方法。
    public int Calculate(int n)
    {
        if (n <= 1)
        {
            return n;
        }
        else
        {
            return Calculate(n - 1) + Calculate(n - 2);
        }
    }

    public int N { get { return _n; } }
    private int _n;

    public int FibOfN { get { return _fibOfN; } }
    private int _fibOfN;

    ManualResetEvent _doneEvent;
}

public class ThreadPoolExample
{
    static void Main()
    {
        const int FibonacciCalculations = 10;

        // 每個 Fibonacci 對象使用一個事件
        ManualResetEvent[] doneEvents = new ManualResetEvent[FibonacciCalculations];
        Fibonacci[] fibArray = new Fibonacci[FibonacciCalculations];
        Random r = new Random();

        // 使用 ThreadPool 配置和啟動線程:
        Console.WriteLine("launching {0} tasks...", FibonacciCalculations);
        for (int i = 0; i < FibonacciCalculations; i++)
        {
            doneEvents[i] = new ManualResetEvent(false);
            Fibonacci f = new Fibonacci(r.Next(20,40), doneEvents[i]);
            fibArray[i] = f;
            ThreadPool.QueueUserWorkItem(f.ThreadPoolCallback, i);
        }

        // 等待池中的所有線程執行計算...
        WaitHandle.WaitAll(doneEvents);
        Console.WriteLine("Calculations complete.");

        // 顯示結果...
        for (int i= 0; i<FibonacciCalculations; i++)
        {
            Fibonacci f = fibArray[i];
            Console.WriteLine("Fibonacci({0}) = {1}", f.N, f.FibOfN);
        }
    }
}
 
ThreadStartStop.cs
using System;
using System.Threading;

public class Worker
{
    // 啟動線程時調用此方法。
    public void DoWork()
    {
        while (!_shouldStop)
        {
            Console.WriteLine("worker thread: working...");
        }
        Console.WriteLine("worker thread: terminating gracefully.");
    }
    public void RequestStop()
    {
        _shouldStop = true;
    }
    // Volatile 用于向編譯器提示此數據
    // 成員將由多個線程訪問。
    private volatile bool _shouldStop;
}

public class WorkerThreadExample
{
    static void Main()
    {
        // 創建線程對象。這不會啟動該線程。
        Worker workerObject = new Worker();
        Thread workerThread = new Thread(workerObject.DoWork);

        // 啟動輔助線程。
        workerThread.Start();
        Console.WriteLine("main thread: Starting worker thread...");

        // 循環直至輔助線程激活。
        while (!workerThread.IsAlive);

        // 為主線程設置 1 毫秒的休眠,
        // 以使輔助線程完成某項工作。
        Thread.Sleep(1);

        // 請求輔助線程自行停止:
        workerObject.RequestStop();

        // 使用 Join 方法阻塞當前線程, 
        // 直至對象的線程終止。
        workerThread.Join();
        Console.WriteLine("main thread: Worker thread has terminated.");
    }
}


 
ThreadSync.cs
using System;
using System.Threading;
using System.Collections;
using System.Collections.Generic;

// 將線程同步事件封裝在此類中, 
// 以便于將這些事件傳遞給 Consumer 和
// Producer 類。
public class SyncEvents
{
    public SyncEvents()
    {
        // AutoResetEvent 用于“新項”事件,因為
        // 我們希望每當使用者線程響應此事件時,
        // 此事件就會自動重置。
        _newItemEvent = new AutoResetEvent(false);

        // ManualResetEvent 用于“退出”事件,因為
        // 我們希望發出此事件的信號時有多個線程響應。
        // 如果使用 AutoResetEvent,事件
        // 對象將在單個線程作出響應之后恢復為 
        // 未發信號的狀態,而其他線程將
        // 無法終止。
        _exitThreadEvent = new ManualResetEvent(false);

        // 這兩個事件也放在一個 WaitHandle 數組中,以便
        // 使用者線程可以使用 WaitAny 方法
        // 阻塞這兩個事件。
        _eventArray = new WaitHandle[2];
        _eventArray[0] = _newItemEvent;
        _eventArray[1] = _exitThreadEvent;
    }

    // 公共屬性允許對事件進行安全訪問。
    public EventWaitHandle ExitThreadEvent
    {
        get { return _exitThreadEvent; }
    }
    public EventWaitHandle NewItemEvent
    {
        get { return _newItemEvent; }
    }
    public WaitHandle[] EventArray
    {
        get { return _eventArray; }
    }

    private EventWaitHandle _newItemEvent;
    private EventWaitHandle _exitThreadEvent;
    private WaitHandle[] _eventArray;
}

// Producer 類(使用一個輔助線程)
// 將項異步添加到隊列中,共添加 20 個項。
public class Producer 
{
    public Producer(Queue<int> q, SyncEvents e)
    {
        _queue = q;
        _syncEvents = e;
    }
    public void ThreadRun()
    {
        int count = 0;
        Random r = new Random();
        while (!_syncEvents.ExitThreadEvent.WaitOne(0, false))
        {
            lock (((ICollection)_queue).SyncRoot)
            {
                while (_queue.Count < 20)
                {
                    _queue.Enqueue(r.Next(0, 100));
                    _syncEvents.NewItemEvent.Set();
                    count++;
                }
            }
        }
        Console.WriteLine("Producer thread: produced {0} items", count);
    }
    private Queue<int> _queue;
    private SyncEvents _syncEvents;
}

// Consumer 類通過自己的輔助線程使用隊列
// 中的項。Producer 類使用 NewItemEvent 
// 將新項通知 Consumer 類。
public class Consumer
{
    public Consumer(Queue<int> q, SyncEvents e)
    {
        _queue = q;
        _syncEvents = e;
    }
    public void ThreadRun()
    {
        int count = 0;
        while (WaitHandle.WaitAny(_syncEvents.EventArray) != 1)
        {
            lock (((ICollection)_queue).SyncRoot)
            {
                int item = _queue.Dequeue();
            }
            count++;
        }
        Console.WriteLine("Consumer Thread: consumed {0} items", count);
    }
    private Queue<int> _queue;
    private SyncEvents _syncEvents;
}

public class ThreadSyncSample
{
    private static void ShowQueueContents(Queue<int> q)
    {
        // 對集合進行枚舉本來就不是線程安全的,
        // 因此在整個枚舉過程中鎖定集合以防止
        // 使用者和制造者線程修改內容
        // 是絕對必要的。(此方法僅由
        // 主線程調用。)
        lock (((ICollection)q).SyncRoot)
        {
            foreach (int i in q)
            {
                Console.Write("{0} ", i);
            }
        }
        Console.WriteLine();
    }

    static void Main()
    {
        // 配置結構,該結構包含線程同步
        // 所需的事件信息。
        SyncEvents syncEvents = new SyncEvents();

        // 泛型隊列集合用于存儲要制造和使用的
        // 項。此例中使用的是“int”。
        Queue<int> queue = new Queue<int>();

        // 創建對象,一個用于制造項,一個用于
        // 使用項。將隊列和線程同步事件傳遞給
        // 這兩個對象。
        Console.WriteLine("Configuring worker threads...");
        Producer producer = new Producer(queue, syncEvents);
        Consumer consumer = new Consumer(queue, syncEvents);

        // 為制造者對象和使用者對象創建線程
        // 對象。此步驟并不創建或啟動
        // 實際線程。
        Thread producerThread = new Thread(producer.ThreadRun);
        Thread consumerThread = new Thread(consumer.ThreadRun);

        // 創建和啟動兩個線程。
        Console.WriteLine("Launching producer and consumer threads...");        
        producerThread.Start();
        consumerThread.Start();

        // 為制造者線程和使用者線程設置 10 秒的運行時間。
        // 使用主線程(執行此方法的線程)
        // 每隔 2.5 秒顯示一次隊列內容。
        for (int i = 0; i < 4; i++)
        {
            Thread.Sleep(2500);
            ShowQueueContents(queue);
        }

        // 向使用者線程和制造者線程發出終止信號。
        // 這兩個線程都會響應,由于 ExitThreadEvent 是
        // 手動重置的事件,因此除非顯式重置,否則將保持“設置”。
        Console.WriteLine("Signaling threads to terminate...");
        syncEvents.ExitThreadEvent.Set();

        // 使用 Join 阻塞主線程,首先阻塞到制造者線程
        // 終止,然后阻塞到使用者線程終止。
        Console.WriteLine("main thread waiting for threads to finish...");
        producerThread.Join();
        consumerThread.Join();
    }
}
 
 本文由用戶 wen5 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!