此篇簡單介紹執行緒(Thread)。
此篇程式都運行在同一個主程式內,若要個別瞭解只需註解掉主程式內的程式碼。
主程式 :
using System;
using System.Threading;
namespace TreadDay1
{
//底下是個測試多執行緒的簡單範例,示範如何建立一個執行緒來執行某件背景工作。有個名詞得先說一下:
// 負責執行背景工作的執行緒又稱為「工作執行緒」(worker thread)。之所以不說「背景執行緒」,
// 是為了避免跟執行緒集區有關的前景、背景執行緒概念混淆。
class Program
{
static void Main(string[] args)
{
// 指定方法建立執行緒
Thread t1 = new Thread(MyBackgroundTask);
Thread t2 = new Thread(MyBackgroundTask);
Thread t3 = new Thread(MyBackgroundTask);
// 啟動執行緒 若沒有特殊處理執行續會自動被終止或釋放
t1.Start();
t2.Start();
t3.Start();
// 等待執行緒結束 Main主程序執行到這行會等待t1執行緒執行完畢後才繼續往下
// 但其它執行緒Tread不受到此指令引響
t1.Join();
// 讓目前執行緒休息
Thread.Sleep(1);
for (int i = 0; i < 500; i++)
{
Console.Write(".");
}
Console.WriteLine();
// 不同執行緒共享變數
new SharedStateDemo().Run();
// 使用Lock鎖定執行緒來執行
new Locker().Run();
// 使用無窮迴圈測試背景執行緒
new Background().Run();
// 使用.NET 所提供靜態方法 CLR執行緒集區 由CLR來幫忙管理執行緒
ThreadPool.QueueUserWorkItem(DownloadFile,"xyz.iso");
Console.ReadLine();
}
static void MyBackgroundTask()
{
for (int i = 0; i < 500; i++)
{
Console.Write("[" + Thread.CurrentThread.ManagedThreadId + "]");
}
}
static void DownloadFile(object fileName)
{
Console.WriteLine("Downloading file {0}", fileName);
}
}
}
不同執行緒共享變數的類 : SharedStateDemo.cs
using System;
using System.Threading;
namespace TreadDay1
{
class SharedStateDemo
{
private int _itemcount = 0; // 已加入購物車的商品數量。
public void Run()
{
var t1 = new Thread(this.AddToCart);
var t2 = new Thread(this.AddToCart);
t1.Start(300);
t2.Start(100);
//如果 t1 和 t2 這兩條執行緒是依照它們啟動的順序先後完成任務,執行結果的第一列顯示地購物車商品數量應為 1,
//第二列的數量才是 2。可是現在卻全都是 2,這是因為 t1 先啟動,進入 AddCart 函式之後,把 itemCount 加一,
//然後進入一段模擬長時間工作的延遲(300ms)。此時 t2 也已經啟動了,也把 itemCount 加一了(其值為 2),
//然後也進入一段延遲(100ms)。但由於 t2 的延遲時間較短,比 t1 更快執行完畢(後發而先至),
//因此執行結果畫面中的第一列文字其實是由執行緒 t2 輸出的。接下來,t1 也跑完了,但此時的 itemCount 已經被 t2 改成了 2,
//所以輸出的結果自然就一樣了。
}
private void AddToCart(object simulateDelay)
{
this._itemcount++;
/*
* 用 Thread.Sleep 來模擬這項工作所花的時間,時間長短
* 由呼叫端傳入的 simulateDelay 參數指定,以便藉由改變
* 此參數來觀察共享變數值的變化。
*/
Thread.Sleep((int)simulateDelay);
Console.WriteLine("Items in cart: {0}", _itemcount);
}
}
}
使用Lock鎖定執行緒來執行 : Locker.cs
using System;
using System.Threading;
namespace TreadDay1
{
class Locker
{
private int _itemcount = 0;
private object _locker = new Object(); // 用於獨佔鎖定的物件
public void Run()
{
var t1 = new Thread(AddToCart);
var t2 = new Thread(AddToCart);
t1.Start(300);
t2.Start(100);
}
private void AddToCart(object simulateDelay)
{
Console.WriteLine("Enter thread {0}", // 顯示目前所在的執行緒編號
Thread.CurrentThread.ManagedThreadId);
lock (this._locker) // 利用 locker 物件來鎖定程式區塊
{
this._itemcount++;
Thread.Sleep((int)simulateDelay);
Console.WriteLine("Items in cart: {0} on thread {1}",
this._itemcount, Thread.CurrentThread.ManagedThreadId);
}
}
}
}
使用無窮迴圈測試背景執行緒 : Background.cs
using System;
using System.Threading;
namespace TreadDay1
{
//背景執行緒
class Background
{
public int MyProperty { get; set; }
public void Run()
{
Thread t = new Thread(MyWork);
t.IsBackground = true;
t.Start();
Console.WriteLine("IsBackground");
// 若 t 是前景執行緒,此應用程式不會結束,除非手動將它關閉;
// 若 t 是背景執行緒,此應用程式會立刻結束。
}
static void MyWork()
{
while (true)
;
}
}
}
多多指教!! 歡迎交流!!
你不知道自己不知道,那你會以為你知道