Winform中C#線程控制的四種常見情況分析
Winform界面中,將事務放在新開的線程中操作是十分有用的做法,因為這樣可以增加用戶體驗,減少耗時。對這些C#線程的控制,常常有下面這四種情況:
1. 啟動線程;
2. 線程間通訊;
3. 線程終止;
4. 線程中的異常處理;
下面總結(jié)一些上面這些C#線程操作的常用方法。
C#線程控制1. 啟動C#線程
◆如果是需要很頻繁的開線程,會使用線程池(微軟的或自己寫的)
◆Thread.Start(參數(shù)object);
◆或者用對象提供的BeginXXXX()這種都是異步,也算多線程啟動.
C#線程控制2. C#線程間通訊◆委托,事件這些比較常用,并且對object的多線程處理需要謹慎,可能用到lock(object){}.
◆主要是通過線程同步或者回調(diào)方法(或者說是委托)來實現(xiàn)
C#線程控制3. 線程終止◆線程的終止,用事件AUTORESET之類
◆可以用Thread.ManualEvent().Reset()/Set()/WaitOne()方法來判斷和等待C#線程控制4. 線程中的異常處理
◆線程中的異常通過事件傳回到主線程處理
◆還是寫log吧,多線程debug比較難,還是逐步log比較好.
用于C#線程通訊的lock關(guān)鍵字
下面的示例演示使用 lock 關(guān)鍵字以及 AutoResetEvent 和 ManualResetEvent 類對主線程和兩個輔助線程進行線程同步。
該示例創(chuàng)建兩個輔助線程。一個線程生成元素并將它們存儲在非線程安全的泛型隊列中。有關(guān)更多信息,請參見 Queue。另一個線程使用此隊列中的項。另外,主線程定期顯示隊列的內(nèi)容,因此該隊列被三個線程訪問。lock 關(guān)鍵字用于同步對隊列的訪問,以確保隊列的狀態(tài)沒有被破壞。
除了用 lock 關(guān)鍵字來阻止同時訪問外,還用兩個事件對象提供進一步的同步。一個事件對象用來通知輔助線程終止,另一個事件對象由制造者線程用來在有新項添加到隊列中時通知使用者線程。這兩個事件對象封裝在一個名為 SyncEvents 的類中。這使事件可以輕松傳遞到表示制造者線程和使用者線程的對象。SyncEvents 類是按如下方式定義的:
C# code
- using System;
- using System.Threading;
- using System.Collections;
- using System.Collections.Generic;
- public class SyncEvents
- {
- public SyncEvents()
- {
- _newItemEvent = new AutoResetEvent(false);
- _exitThreadEvent = new ManualResetEvent(false);
- _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;
- }
- public class Producer
- {
- public Producer(Queue <int> q, SyncEvents e)
- {
- _queue = q;
- _syncEvents = e;
- }
- // Producer.ThreadRun
- 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;
- }
- public class Consumer
- {
- public Consumer(Queue <int> q, SyncEvents e)
- {
- _queue = q;
- _syncEvents = e;
- }
- // Consumer.ThreadRun
- 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 item in q)
- {
- Console.Write("{0} ", item);
- }
- }
- Console.WriteLine();
- }
- static void Main()
- {
- Queue <int> queue = new Queue <int>();
- SyncEvents syncEvents = new SyncEvents();
- 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();
- for (int i=0; i <4; i++)
- {
- Thread.Sleep(2500);
- ShowQueueContents(queue);
- }
- Console.WriteLine("Signaling threads to terminate...");
- syncEvents.ExitThreadEvent.Set();
- producerThread.Join();
- consumerThread.Join();
- }
- }
【編輯推薦】