記錄,做到溫故而知新。
一、相關概念:
什麼是進程?
當一個程式開始運行時,它就是一個進程,進程包括運行中的程式和程式所使用到的記憶體和系統資源。而一個進程又是由多個線程所組成的。
什麼是線程?
線程是程式中的一個執行流,每個線程都有自己的專有寄存器(棧指標、程式計數器等),但代碼區是共用的,即不同的線程可以執行同樣的函數。
什麼是多線程?
多線程是指程式中包含多個執行流,即在一個程式中可以同時運行多個不同的線程來執行不同的任務,也就是說允許單個程式建立多個並存執行的線程來完成各自的任務。
多線程的好處:
可以提高CPU的利用率。在多線程程式中,一個線程必須等待的時候,CPU可以運行其它的線程而不是等待,這樣就大大提高了程式的效率。
多線程編程有好處,也有不好的地方,如:
線程也是對象,需要佔用記憶體,線程越多佔用記憶體越多;
多線程需要協調和管理,所以需要CPU時間跟蹤線程;
線程之間對共用資源的訪問會相互影響,必須解決競用共用資源的問題;
線程太多會導致控制太複雜,最終可能帶來產生Bug的風險。
二、Thread類
先來理解下Thread類,這是實現多線程編程的基礎。Thread類位於System.Threading命名空間,其建構函式為:
public Thread(ParameterrizedThreadStart start)
public Thread(ThreadStart start)
public Thread(ParameterizedThreadStart start, int maxStackSize)
public Thread(ThreadStart start, int maxStackSize)
這些建構函式涉及3種類型的參數:
1)ParameterizedThreadStart:是一個委託類型,表示此線程開始執行時要調用的方法,支援向調用的方法傳遞一個參數。
2)ThreadStart:是一個委託類型,表示此線程開始執行時要調用的方法沒有參數的委託類型,不支援向調用的方法傳遞一個參數。
3)maxStackSize:表示線程要使用的最大堆棧大小,如果為0剛使用可執行檔的檔案頭中指定的預設最大堆棧大小。
Thread類有幾個至關重要的方法,描述如下:
Start():啟動線程;
Sleep(int):靜態方法,暫停當前線程指定的毫秒數;
Abort():通常使用該方法來終止一個線程;
Suspend():該方法並不終止未完成的線程,它僅僅掛起線程,以後還可恢複;
Resume():恢複被Suspend()方法掛起的線程的執行。
Thread類基本的使用代碼如下:
View Code
using System;
using System.Threading;
namespace ProgrammingCSharp4
{
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine("[主線程id:{0}]",Thread.CurrentThread.ManagedThreadId);
Thread thread1 = new Thread(Print);
thread1.Start();
Thread thread2 = new Thread(PrintEx);
thread2.Start("測試");
Console.ReadKey(true);
}
public static void Print()
{
int threadId = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("[當前線程id:{0}]{1}",threadId,DateTime.Now.ToShortTimeString());
}
public static void PrintEx(object obj)
{
int threadId = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("[當前線程id:{0}]{1}",threadId,obj);
}
}
}
三、線程池的使用
C#中,我們可以通過一種叫做“池(Pool)”的技術來最佳化對象的使用,其原理是預先建立一定數量的對象放在“池”裡,在對象被請求的時候,某個對象被從“池”中取出供使用,使用完畢再重新放回“池”中,等待下一次的請求。我們可以自己實現這樣的線程池,也可以使用.NET Framework為我們所提供的線程池,它叫做TreadPool,位於System.Threading命名空間。
需要注意的是線程池中的線程均為後台線程,即它們的IsBackground屬性為True。也就是說在所有的前台線程都已經退出後,ThreadPool中的線程不會讓應用程式繼續保持運行。
所以當我們執行一些簡單的、耗時短暫的任務時,才應該使用到線程池,在下面的情況下則不應該使用線程池技術:
Ø 當需要建立一個前台線程時;
Ø 線程池中的線程都是預設優先順序的,因此當需要建立具有特定優先順序的線程時就不應該使用線程池;
Ø 當需要某個任務只和特定的線程關聯時,因為無法選擇執行任務時使用的是哪一個具體的線程;
Ø 當需要中止特定的線程時不應使用線程池,它不提供這個功能;
Ø 線程執行時間比較長時;
要使用ThreadPool中的線程,需要使用TheadPool.QueueUserWorkItem這個靜態方法指定線程要調用的方法,該方法有兩個重載版本:
public static bool QueueUserWorkItem(WaitCallBack callBack)
public static bool QueueUserWorkItem(WaitCallBack callBack,object state)
WaitCallBack是一個委託類型,下面是線程池使用的例子:
View Code
using System;
using System.Threading;
namespace AsynchronousSample
{
class Program
{
public static void Main(string[] args)
{
ThreadPool.QueueUserWorkItem(Counter);
ThreadPool.QueueUserWorkItem(Counter,"AsynchronousSample Test");
Console.WriteLine("[Thread ID = {0}]The main thread is started.",Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(500);
Console.WriteLine("The main thread is closed.");
Console.ReadKey(true);
}
private static void Counter(object state)
{
Console.WriteLine("Counting begins, from 1 to 100:");
Console.WriteLine("the Parameter is:{0}",state);
for(int counter = 0 ; counter <100;counter++)
{
if(null==state)
{
Console.WriteLine("[Thread ID = {0}] {1}",Thread.CurrentThread.ManagedThreadId,counter);
}else
{
Console.WriteLine("[Thread ID = {0}] {1}",Thread.CurrentThread.ManagedThreadId,state);
}
Thread.Sleep(100);
}
}
}
}
未完待續,下次接著複習Thread的相關屬性與用法。