1. 程式人生 > >c#多執行緒進階

c#多執行緒進階

一、多執行緒傳遞引數的方法
整理自:https://www.cnblogs.com/shi5588/p/6130536.html

1 、帶引數的委託方法來傳遞引數

       static void Main(string[] args)
        {
            var d = new Data { Message = "中國" };
            //通過帶引數的委託方法來傳遞引數 ParameterizedThreadStart
            var t2 = new Thread(ThreadMainWithParameters);
            t2.Start(d); 
            System.Console.ReadLine();
        }
        static void ThreadMainWithParameters(object o) // 此處定義必須使用Object
        {
            Data d = (Data)o;
            Console.WriteLine("Running in a thread, received {0}", d.Message);
        }

2 通過成員方法和帶引數的建構函式傳引數

  class Program
    {
        static void Main(string[] args)
        {
            var obj = new MyThread("廣東");
            var t3 = new Thread(obj.ThreadMain);
            t3.Start();
            Console.ReadLine();
        }
   }
    public class MyThread                                                                                                                                                                                                                                                                                                                                                                                                                             
    {
        private string data;
        public MyThread(string data)
        {
            this.data = data;
        }
        /// <summary>
        /// 執行緒方法
        /// </summary>
        public void ThreadMain()
        {
            Console.WriteLine("Running in a thread, data: {0}", data);
        }
    }
    public struct Data
    {
        public string Message;
    }

二、前臺執行緒和後臺執行緒

1.預設情況下,你自己顯示建立的執行緒是前臺執行緒。前臺執行緒保持這個應用程式一直存活只要其中任意一個正在執行,而後臺執行緒不是這樣的。一旦所有的前臺執行緒完成,這個應用程式就結束了,
2.任何正在執行的後臺執行緒立刻終止。 一個執行緒前臺/後臺的狀態跟它的優先順序和配置的執行時間沒有關聯。
3.你可以使用執行緒的IsBackgroud屬性查詢或改變一個執行緒的後臺狀態。
4.程會等待所有的前臺執行緒完成後再結束工作,但是如果只剩下後臺執行緒,則會直接結束工作。

前臺執行緒和後臺執行緒的區別和聯絡:
1、後臺執行緒不會阻止程序的終止。屬於某個程序的所有前臺執行緒都終止後,該程序就會被終止。所有剩餘的後臺執行緒都會停止且不會完成。
2、可以在任何時候將前臺執行緒修改為後臺執行緒,方式是設定Thread.IsBackground 屬性。
3、不管是前臺執行緒還是後臺執行緒,如果執行緒內出現了異常,都會導致程序的終止。
4、託管執行緒池中的執行緒都是後臺執行緒,使用new Thread方式建立的執行緒預設都是前臺執行緒。

static void Main(string[] args)
{
    Thread t = new Thread(() => Console.ReadKey());
    if (args.Length > 0)//如果Main方法沒有傳入引數
    {
        //設定執行緒為後臺執行緒,等待使用者輸入。
        //因為主執行緒在t.Start()執行之後就會終止,
        //所以後臺執行緒t會在主執行緒退出之後,立即終止,應用程式就會結束。
        t.IsBackground = true;
    }
    t.Start();
}

三、執行緒優先順序問題

整理自:http://www.cnblogs.com/jackson0714/p/5103898.html#autoid-5-0-0
一個執行緒的優先順序決定了在作業系統中它可以得到多少相對其他執行緒的執行時間,下面是執行緒優先順序的等級:

// Summary:
// Specifies the scheduling priority of a System.Threading.Thread.
[Serializable]
[ComVisible(true)]
public enum ThreadPriority
{
    Lowest = 0,
    BelowNormal = 1,
    Normal = 2,
    AboveNormal = 3,
    Highest = 4,
}

當多執行緒同時是啟用的,執行緒優先順序是很重要的。
注意:提高執行緒優先順序時,需要非常小心,這將可能導致其他執行緒對資源訪問的飢餓狀態的問題。
當提升一個執行緒的優先順序時,不會使它執行實時工作,因為它被應用程式的程序優先順序限制了。為了執行實時工作,你也必須通過使用System.Diagnostices的Process類來提升程序的優先順序:

using (Process p = Process.GetCurrentProcess())
{
    p.PriorityClass = ProcessPriorityClass.High;
}

ProcessPriorityClass.High事實上是優先順序最高的一檔:實時。設定一個程序優先順序到實時狀態將會導致其他執行緒無法獲得CPU時間片。如果你的應用程式意外地進入一個無限迴圈的狀態,你甚至會發現操作被鎖住了,只有電源鍵能夠拯救你了。針對這個原因,High通常對於實時應用程式是最好的選擇。

如果你的實時應用程式有一個使用者介面,提高程式的優先順序將會使重新整理介面佔用昂貴的CPU的時間,且會使整個系統變得執行緩慢(尤其是UI很複雜的時候)。降低主執行緒優先順序且提升程序的優先順序來確保實時執行緒不會被介面重繪所搶佔,但是不會解決其他程序對CPU訪問缺乏的問題,因為作業系統整體上會一直分配不成比例的資源給程序。一個理想的解決方案是讓實時執行緒和使用者介面用不同的優先順序執行在不同的程序中,通過遠端和記憶體對映檔案來通訊。即使提高了程序優先順序,在託管環境中處理硬實時系統需求還是對適用性有限制。此外,潛藏的問題會被自動垃圾回收引進,作業系統會遇到新的挑戰,即使是非託管程式碼,使用專用硬體或者特殊的實時平臺,那將被最好的解決。

四、執行緒池

1、執行緒池是一種多執行緒處理形式,處理過程中將任務新增到佇列,然後在建立執行緒後自動啟動這些任務
2、每個執行緒都使用預設的堆疊大小,以預設的優先順序執行,並處於多執行緒單元中。
3、如果某個執行緒在託管程式碼中空閒(如正在等待某個事件),則執行緒池將插入另一個輔助執行緒來使所有處理器保持繁忙。如果所有執行緒池執行緒都始終保持繁忙,但佇列中包含掛起的工作,則執行緒池將在一段時間後建立另一個輔助執行緒但執行緒的數目永遠不會超過最大值。超過最大值的執行緒可以排隊,但他們要等到其他執行緒完成後才啟動。
4、建立太多的執行緒是有限制的,在這種情況下新的操作將在佇列中等待直到執行緒池中的工作執行緒有能力來執行它們。
5、當停止向執行緒池中放置新操作時,執行緒池最終會刪除一定時間後過期的不再使用的執行緒。這將釋放所有那些不再需要的系統資源。
6、執行緒池的用途是執行執行時間短的操作。使用執行緒池可以減少並行度耗費,及節省作業系統資源。
我們只使用較少的執行緒,但是以比平常更慢的速度來執行非同步操作, ,使用一定數量的可用的工作執行緒批量處理這些操作。如果操作能快速地完成則比較適用執行緒!池,但是執行長時間執行的計算密集型操作則會降低效能。

當使用執行緒池時需要注意下面的事情:

1、你不能設定一個執行緒的名字,因為設定執行緒的名字將會使除錯更困難(當你在VS執行緒視窗中除錯時,即使你可以附加一個描述)。
2、執行緒池中的執行緒總是後臺執行緒(這通常不是問題)。 3、在應用程式的開始期間,阻塞一個執行緒可能會觸發一個延遲,除非你呼叫ThreadPool.SetMinThreads
4、你不能任意地改變池中的執行緒的優先順序-因為當它釋放會池中的時候,優先順序會被還原為正常狀態。
5、你可以通過屬性Thread.CurrentThread.IsThreadPoolThread的屬性查詢執行緒是否是正在執行的一個池中的執行緒

ThreadPool.SetMinThreads:
task預設對執行緒的排程是逐步增加的,連續多次執行併發執行緒,會提高佔用的執行緒數,而等若干秒不執行,執行緒數又會降低。這樣,會影響程式多次執行的效率。
即使使用了TaskCreationOptions.LongRunning引數,依然效率偏低。對於一些固定執行時間的執行緒,我們可以提高執行緒池的最小執行緒數,來顯著提高task多執行緒的效率。
ThreadPool.SetMinThreads(100, 100);
提高最小執行緒數之後,可以不使用LongRunning引數。

未完待續。。。