C#線程處理


  C#支持通過多線程並行地執行代碼,一個線程有它獨立的執行路徑,能夠與其它的線程同時地運行。一個C#程序開始於一個單線程,這個單線程是被CLR和操作系統(也稱為“主線程”)自動創建的,並具有多線程創建額外的線程。
  除非被指定,否則所有的例子都假定以下命名空間被引用了:

using System;
using System.Threading;

C#開啟線程的方法有:

  • 異步委托
  • 通過Thread類
  • 線程池
  • 任務

  總的來說其實線程的開啟基本都涉及到委托的使用。

一、異步委托開啟線程

首先來看一個比較簡單的例子,采用第一種開啟線程的方法——異步委托

using System;
using System.Threading;

namespace Study
{
    class Program
    {
        static void test()
        {
            Console.WriteLine("TestThread");
        }
        static void Main(string[] args)
        {
            Action a = test;
            a.BeginInvoke(null, null);
            Console.WriteLine("MainThread");
            Console.ReadLine();
        }
    }
}

  編譯運行,發現結果與預期有所不同。結果如下圖
Thread
  如果按着逐行運行代碼的方式,那么應該是先輸出TestThread,但是結果卻是先輸出MainThread。
  將a.BeginInvoke(null,null);Console.WriteLine("MainThread");對調位置之后,結果和之前的依然一致。這就說明,異步委托開啟的線程是和主線程同時同步進行的。
  Action委托是指向一個沒有返回值的函數,那么假設一個線程,我們需要取得他的返回結果並輸出,那么就要用到Func委托。
  看下面的源碼

using System;
using System.Threading;

namespace SummerStudy
{
    class Program
    {
        static string test(int i, string str)
        {
            Console.WriteLine("TestThread" + "\t參數i是:" + i);
            return str;
        }
        static void Main(string[] args)
        {
            Func<int, string, string> a = test;
            IAsyncResult res = a.BeginInvoke(1, "返回值", null, null);
            string o = a.EndInvoke(res);
            Console.WriteLine("MainThread\t" + "線程返回值是:" + o);
            Console.ReadLine();
        }
}

Thread
同時異步委托開啟線程中,判斷線程是否結束的方法也有兩種,一種是利用IAsyncResult的IsCompleted方法,一種是使用方法進行線程結束判斷。
  具體使用方法如下。

  1. IsCompleted(bool)
IAsyncResult ia = a.BeginInvoke()
if(ia.IsCompleted == false)
{
    //GoOn
}
  1. AsyncWaitHandle
IAsyncResult ia = a.BeginInvoke()
ia.AsyncWaitHandle.WaitOne(Time);//Time為等待時間,超時后才會運行下一行代碼,未完成直接跳出返回false

  或者通過自定義方法,BeginInvoke中倒數第二個參數是一個委托,傳遞一個函數,在線程結束之后會自動的調用。

static string Test(int a)
{

}
Func<int, string> a = Test;
IAsyncResult ia = a.BeginInvoke(100, CallBack, a);
static void CallBack(IAsyncResult ar)
{
    Func<int, string> a = ia.AsyncState as Func<int, string>;
    string res = a.EndInvoke(ar);
}

  在使用Lambda表達式作為委托的時候,最后一個參數可以為空,因為Lambda表達式可以訪問外部變量。

二、使用Thread類開啟線程

  使用Thread類創建一個實例,它的構造方法中需要傳遞一個委托。通過委托綁定線程。
  直接上代碼

using System;
using System.Threading;

namespace Study
{
    class Program
    {
        static void test()
        {
            Console.WriteLine("Thread");
            Thread.Sleep(2000);
            Console.WriteLine("TimeOver");
        }
        static void Main(string[] args)
        {
            Thread t = new Thread(test);
            t.Start();
            Console.WriteLine("Main");
            Console.Read();
        }
    }
}

Thread
  對於需要傳遞參數的委托,則必須制定參數類型為object,在線程Start方法中傳遞參數

namespace SummerStudy
{
    class Program
    {
        static void test(object c)
        {
            int id = Thread.CurrentThread.ManagedThreadId;
            Console.WriteLine("Thread,\t線程id為" + id + ",\t參數是:" + c);
            Thread.Sleep(2000);
            Console.WriteLine("TimeOver");

        }
        static void Main(string[] args)
        {
            Thread t = new Thread(test);
            t.Start("xxx.avi");
            Console.WriteLine("Main");
            Console.Read();
        }
    }
}

Thread
  當然你也可以自定義一個類,在類中自定義數據傳遞。

三、線程池

  這種方法有助於節省時間,具體使用方法如下

using System;
using System.Threading;

namespace SummerStudy
{
    class Program
    {
        static void test(object c)
        {
            int id = Thread.CurrentThread.ManagedThreadId;
            Console.WriteLine("Thread,\t線程id為" + id + ",\t參數是:" + c);
            Thread.Sleep(2000);
            Console.WriteLine("TimeOver");

        }
        static void Main(string[] args)
        {
            ThreadPool.QueueUserWorkItem(test, "asfasf");
            Console.Read();
        }
    }
}

  其中委托必須要有一個參數,無論是否使用該參數。且只適用於使用時間短的線程,不能改變優先級

四、任務

  使用Task類開啟線程,還有TaskFactory創建
  Task類實例

using System;
using System.Threading;
using System.Threading.Tasks;

namespace SummerStudy
{
    class Program
    {
        static void test(object c)
        {
            int id = Thread.CurrentThread.ManagedThreadId;
            Console.WriteLine("Thread,\t線程id為" + id);
            Thread.Sleep(2000);
            Console.WriteLine("TimeOver");

        }
        static void Main(string[] args)
        {
            Task t = new Task(test, "Asfgasg");
            t.Start();

            //或者

            TaskFactory tf = new TaskFactory();

            Task t1 = tf.StartNew(test);
            Console.Read();
        }
    }
}

我的掘金:WarrenRyan

我的簡書:WarrenRyan

歡迎關注我的博客獲得第一時間更新 https://blog.tity.xyz

我的Github:WarrenRyan

我的博客園:WarrenRyan


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM