C 支持通過多線程並行地執行代碼,一個線程有它獨立的執行路徑,能夠與其它的線程同時地運行。一個C 程式開始於一個單線程,這個單線程是被CLR和操作系統(也稱為“主線程”)自動創建的,並具有多線程創建額外的線程。 除非被指定,否則所有的例子都假定以下命名 ...
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();
}
}
}
編譯運行,發現結果與預期有所不同。結果如下圖
如果按著逐行運行代碼的方式,那麼應該是先輸出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();
}
}
同時非同步委托開啟線程中,判斷線程是否結束的方法也有兩種,一種是利用IAsyncResult的IsCompleted方法,一種是使用方法進行線程結束判斷。
具體使用方法如下。
- IsCompleted(bool)
IAsyncResult ia = a.BeginInvoke()
if(ia.IsCompleted == false)
{
//GoOn
}
- 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();
}
}
}
對於需要傳遞參數的委托,則必須制定參數類型為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();
}
}
}
當然你也可以自定義一個類,在類中自定義數據傳遞。
三、線程池
這種方法有助於節省時間,具體使用方法如下
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