首頁 > 軟體

C#實現多執行緒程式設計的簡單案例

2022-04-18 22:02:15

一、使用執行緒的理由

1、可以使用執行緒將程式碼同其他程式碼隔離,提高應用程式的可靠性。
2、可以使用執行緒來簡化編碼。
3、可以使用執行緒來實現並行執行。

二、基本知識

1、程序與執行緒:程序作為作業系統執行程式的基本單位,擁有應用程式的資源,程序包含執行緒,程序的資源被執行緒共用,執行緒不擁有資源。
2、前臺執行緒和後臺執行緒:通過Thread類新建執行緒預設為前臺執行緒。當所有前臺執行緒關閉時,所有的後臺執行緒也會被直接終止,不會丟擲異常。
3、掛起(Suspend)和喚醒(Resume):由於執行緒的執行順序和程式的執行情況不可預知,所以使用掛起和喚醒容易發生死鎖的情況,在實際應用中應該儘量少用。
4、阻塞執行緒:Join,阻塞呼叫執行緒,直到該執行緒終止。
5、終止執行緒:Abort:丟擲 ThreadAbortException 異常讓執行緒終止,終止後的執行緒不可喚醒。Interrupt:丟擲 ThreadInterruptException 異常讓執行緒終止,通過捕獲異常可以繼續執行。
6、執行緒優先順序:Highest AboveNormal Normal BelowNormal Lowest ,預設為Normal。

三、執行緒的使用

執行緒函數通過委託傳遞,可以不帶引數,也可以帶引數(只能有一個引數),可以用一個類或結構體封裝引數。

案例:

class Program
    {
        static void Main(string[] args)
        {
            Thread t1 = new Thread(new ThreadStart(TestMethod));//建立無引數數執行緒
            Thread t2 = new Thread(new ParameterizedThreadStart(TestMethod));//建立帶引數的執行緒

            //設定為後臺程序
            t1.IsBackground = true;
            t2.IsBackground = true;
            t1.Start();
            t2.Start("hello");
            Console.ReadKey();
        }

        public static void TestMethod()
        {
            Console.WriteLine("不帶引數的執行緒函數");
        }

        //引數要定義為object 型別
        public static void TestMethod(object data)
        {
            string datastr = data as string;
            Console.WriteLine("帶引數的執行緒函數,引數為:{0}", datastr);
        }
    }

四、執行緒池

由於執行緒的建立和銷燬需要耗費一定的開銷,過多的使用執行緒會造成記憶體資源的浪費,出於對效能的考慮,於是引入了執行緒池的概念。執行緒池維護一個請求佇列,執行緒池的程式碼從佇列提取任務,然後委派給執行緒池的一個執行緒執行,執行緒執行完不會被立即銷燬,這樣既可以在後臺執行任務,又可以減少執行緒建立和銷燬所帶來的開銷。
執行緒池執行緒預設為後臺執行緒(IsBackground)。

class Program
    {
        static void Main(string[] args)
        {
            //將工作項加入到執行緒池佇列中,這裡可以傳遞一個執行緒引數
            ThreadPool.QueueUserWorkItem(TestMethod, "Hello");
            Console.ReadKey();
        }

        //執行緒函數
        public static void TestMethod(object data)
        {
            string datastr = data as string;
            Console.WriteLine(datastr);
        }
    }

五、Task類

使用ThreadPool的QueueUserWorkItem()方法發起一次非同步的執行緒執行很簡單,但是該方法最大的問題是沒有一個內建的機制讓你知道操作什麼時候完成,有沒有一個內建的機制在操作完成後獲得一個返回值。為此,可以使用System.Threading.Tasks中的Task類。
構造一個Task<TResult>物件,併為泛型TResult引數傳遞一個操作的返回型別。

class Program
    {
        static void Main(string[] args)
        {
            Task<Int32> t = new Task<Int32>(n => Sum((Int32)n), 1000);
            t.Start();
            t.Wait();
            Console.WriteLine(t.Result);
            Console.ReadKey();
        }

        private static Int32 Sum(Int32 n)
        {
            Int32 sum = 0;
            for (; n > 0; --n)
                checked{ sum += n;} //結果太大,丟擲異常
            return sum;
        }
    }

一個任務完成時,自動啟動一個新任務。
一個任務完成後,它可以啟動另一個任務,下面重寫了前面的程式碼,不阻塞任何執行緒。

class Program
    {
        static void Main(string[] args)
        {
            Task<Int32> t = new Task<Int32>(n => Sum((Int32)n), 1000);
            t.Start();
            //t.Wait();
            Task cwt = t.ContinueWith(task => Console.WriteLine("The result is {0}", t.Result));
            Console.ReadKey();
        }

        private static Int32 Sum(Int32 n)
        {
            Int32 sum = 0;
            for (; n > 0; --n)
                checked { sum += n; } //結果溢位,丟擲異常
            return sum;
        }
    }

六、委託非同步執行

委託的非同步呼叫:BeginInvoke() 和 EndInvoke()

namespace Test
{
    public delegate string MyDelegate(object data);
    class Program
    {
        static void Main(string[] args)
        {
            MyDelegate mydelegate = new MyDelegate(TestMethod);
            IAsyncResult result = mydelegate.BeginInvoke("Thread Param", TestCallback, "Callback Param");

            //非同步執行完成
            string resultstr = mydelegate.EndInvoke(result);
        }

        //執行緒函數
        public static string TestMethod(object data)
        {
            string datastr = data as string;
            Console.WriteLine(datastr);
            return datastr;
        }

        //非同步回撥函數
        public static void TestCallback(IAsyncResult data)
        {
            Console.WriteLine(data.AsyncState);
        }
    }
}

非同步回撥函數在上面執行緒函數執行結束後,將要退出時執行。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com