1. 程式人生 > >[C#]CLR下執行緒的基本介紹與使用

[C#]CLR下執行緒的基本介紹與使用

專用執行緒

由new Thread()建立的執行緒稱為專用執行緒。一般不建議使用專用執行緒,除非有下列情況:

  1. 你需要執行緒執行在非正常的優先順序時。執行緒池中的所有執行緒都是執行在正常優先順序(Normal)下。
  2. 你需要執行緒作為前臺執行緒執行時。執行緒池中的所有執行緒都是後臺執行緒。
  3. 當執行一個非常長時間的計算密集型任務時。
  4. 你想建立一個專用執行緒,並通過Thread.Abort能儘早地結束它的時候
        //create a dedicated thread and have it call a method asynchronously
        private static void DedicatedThread()
        {
            Thread dedicatedThread = new Thread(ComputeBoundOp);
            dedicatedThread.Start(5);

            Console.WriteLine("Main thread: Doing other work here ...");
            Thread.Sleep(8000); //Simulating other work

            dedicatedThread.Join();//等待執行緒終止
        }

        private static void ComputeBoundOp(Object state)
        {
            Console.WriteLine("In ComputeBoundOp: state={0}",state);
            Thread.Sleep(1000);

            //when this method returns,the dedicated thread dies
        }

為什麼要使用執行緒

通常有2個原因:

  1. 為了能及時響應(主要針對客戶端GUI應用),也就是通常說的為了不卡介面
  2. 效能(針對客戶端和伺服器應用): 因為windows是每個CPU分配一個執行緒,並且是多個CPU同時執行這些執行緒,所以在多CPU的機器上使用多執行緒能提升效能

執行緒的優先順序

作業系統的每個執行緒優先順序為0-31(0為最低,31為最高)。當系統要給CPU分配執行緒時,先檢查是否有優先順序為31的,有31的則立即將執行緒分配給CPU.當CPU一直都是在執行優先順序為31的執行緒,而從來不執行0-30優先順序執行緒時,這種情況稱為執行緒的餓死。餓死是高優先順序執行緒佔用大量CPU時間導致,在多處理器的機器上很少出現餓死,因為多個處理器可以同時執行多個高優先順序的執行緒。
系統中為0優先順序執行緒的只有一個,稱為零頁執行緒(zero page thread),它是當系統啟動時,建立的一個特殊執行緒。
windows支援6種程序優先順序: 空閒、低於正常、正常、高於正常、高、實時。你應該儘可能地避免使用實時的優先順序程序,因為實時優先順序很高,可能干擾作業系統任務,如磁碟I/O等。

程序優先順序和相對執行緒優先順序結合後最終的優先順序級別

前臺執行緒與後臺執行緒

CLR認為每個執行緒不是前臺執行緒就是後臺執行緒。當所有的前臺執行緒停止執行時,CLR會強制關閉所有還在執行的後臺執行緒。專用執行緒預設是前臺執行緒,執行緒池的執行緒預設都是後臺執行緒。

Thead t=new Thread(worker);
 t.IsBackground=true;//使執行緒作為後臺執行緒執行

執行緒池

建立和銷燬一個執行緒是比較費時的操作,而且大量的執行緒存在會浪費記憶體以及損傷效能。所以就出現了執行緒池。執行緒池為所有AppDomain所共享。

//執行緒池演示
        private static void ThreadPoolDemonstrate()
        {
            Console.WriteLine("Main thread: queuing an asynchronous operation");
            ThreadPool.QueueUserWorkItem(ComputeBoundOp,6);
            Console.WriteLine("Main thread: Doing other work here ...");
            Thread.Sleep(8000);
        }

執行緒的執行上下文

每個執行緒都有一個執行上下文資料與其關聯。通過控制執行緒的執行上下文,可以實現某些變數只在某些執行緒中使用。

//執行緒的執行上下文
        private static void ExecContext()
        {
            //put some data into the Main thread's logical call context
            CallContext.LogicalSetData("Name", "Cryking");

            //Initiate some work to be done by a thread pool thread
            //The thread pool thread can access the logical call context data
            ThreadPool.QueueUserWorkItem(
                state=> {
                    Console.WriteLine("Name={0}",CallContext.LogicalGetData("Name"));
                });

            //Now,suppress the flowing of the Main thread's execution context
            ExecutionContext.SuppressFlow();

            //Initiate some work to be done by a thread pool thread
            //The thread pool thread CANNOT access the logical call context data
            ThreadPool.QueueUserWorkItem(
                state => {
                    Console.WriteLine("Name={0}", CallContext.LogicalGetData("Name"));
                });

            //Restore the flowing of the Main thread's execution context in case
            //it employs more thread pool threads in the future
            ExecutionContext.RestoreFlow();

        }

執行緒的取消

.NET框架提供了一個標準的執行緒取消模式。

//執行緒的取消演示
        private static void CancellationDemo()
        {
            CancellationTokenSource cts = new CancellationTokenSource();
            cts.Token.Register(() => Console.WriteLine("cancel callback operation 1 ..."));
            cts.Token.Register(() => Console.WriteLine("cancel callback operation 2 ..."));

            //Pass the cancellationToke and the number-to-count-to into the operation
            ThreadPool.QueueUserWorkItem(o => Count(cts.Token, 1000));

            Console.WriteLine("Press <Enter> to cancel the operation.");
            Console.ReadLine();
            cts.Cancel();//If Count returned already,Cancel has no effect on it.
        }

        private static void Count(CancellationToken token, int v)
        {
            for (int count = 0; count < v; count++)
            {
                if (token.IsCancellationRequested)
                {
                    Console.WriteLine("Count is cancelled");
                    break;
                }
                Console.WriteLine(count);
                Thread.Sleep(400);
            }
            Console.WriteLine("Count is done");
        }

Demo執行效果圖

ThreadsDemo