多線程的實現
1、多線程的實現方式
(一):異步委托(本質是微軟會創建一個執行任務的線程,是使用線程池來完成異步任務),實現異步委托的技術大概有三種,投票、等待句柄、異步回調。
1、投票:
public delegate int TakesAWhileDelege(int
ms);
static void Main(string[] args)
{
TakesAWhileDelege dl=TakesAWhile;
IAsyncResult ar = dl.BeginInvoke(1000,null,null);
while (ar.IsCompleted)
Console.WriteLine("委托執行完成");
}
public static int TakesAWhile(int ms)
{
Thread.Sleep(50);
return ms;
}
2、等待句柄(通過AsyncWaitHandle獲取委托的等待句柄WaitHandle,通過該句柄的方法WaitOne方法,即阻止當前線程50毫秒,如果超過50毫秒後該委托還沒有完成就返回false)
public delegate int TakesAWhileDelege(int
ms);
static void Main(string[] args)
{
TakesAWhileDelege dl = TakesAWhile;
IAsyncResult ar = dl.BeginInvoke(1000, null, null);
while (true)
{
if (ar.AsyncWaitHandle.WaitOne(50, false))
break;
}
int result = dl.EndInvoke(ar);
}
public static int TakesAWhile(int ms)
{
Thread.Sleep(50);
return ms;
}
3、異步回調,(t通過BeginInvoke的最後兩個參數,一個是回調函數,一個是)
public delegate int TakesAWhileDelege(int ms);
static void Main(string[] args)
{
TakesAWhileDelege dl = TakesAWhile;
dl.BeginInvoke(1000, completeTake, dl);
Console.WriteLine("adfa");
}
public static void completeTake(IAsyncResult ar)
{
//如果 dl.BeginInvoke(1000, completeTake, dl);中的dl是任何一個參數比如2000,那麼這裡獲取就是
//int num =
(int)ar.AsyncState;
TakesAWhileDelege dlTemp = ar.AsyncState as TakesAWhileDelege;
int result= dlTemp.EndInvoke(ar);
}
public static int TakesAWhile(int ms)
{
Thread.Sleep(50);
return ms;
}
(二):用Thread類創建線程(無參和有參,另外傳遞參數的另一種方法是構建一個類對象,參數作為類對象的成員,然後定義一個threadClass3方法,用於在構造Thread對象的時候傳遞在如:Thread thread2 = new Thread(threadClass3))
我先聲明,用Thread類聲明的線程默認都是前台線程,即及時main函數執行完畢後,只要有一個前台線程沒有完畢,都會不會終止進程,除非你把IsBackground
改為true,改完後則主線程結束,後台線程也跟著結束,不論他有沒有執行完畢
1、普通有參和無參
static void Main(string[]
args)
{
Thread thread1 = new Thread(threadClass1) { Name = "11", IsBackground = false };
thread1.Start();
Thread thread2 = new Thread(threadClass2) { IsBackground = true };
thread2.Start(100);
}
static void threadClass1()
{
}
static void threadClass2(object num)
{
int nums = (int)num;
}
2、通過構建類對象
public class Mythread
{
Private int num;
public void Mythread(int num)
{
This.num=num;
}
Public void threadClass3()
{
//xxxxxxxxxxxxxxxxxxx
}
}
調用線程的時候,
Mythread my1=new Mythread(100);
Thread th1=new Thread(my1.threadClass3);
3、 thread1.Join();
Join:是值阻塞這個thread1進程,一直等待這個進程完成後,才繼續往下執行
thread1.Abort();
Abort:是終止線程
(三):線程池(線程池中的線程必須是後台線程,線程池的進程只能用於時間較短的任務,長時間的線程的話最好新建一個線程)
1、沒有參數
static void Main(string[] args)
{
for (int i = 0; i <= 5; i++)
ThreadPool.QueueUserWorkItem(threadClass);
Console.ReadLine();
}
static void threadClass(object num)
{
Thread.Sleep(3000);
Console.WriteLine(Thread.CurrentThread.ManagedThreadId );
}
2、有參數
構建一個類,參數作為類的成員
public class MythreadA
{
private int num=100;
public MythreadA(int numS)
{
this.num = numS;
}
public void threadClass3(object N)
{
Thread.Sleep(3000);
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":" + num);
}
}
用線程池
static void Main(string[] args)
{
for (int i = 0; i <= 5; i++)
{
MythreadA Mythread1 = new MythreadA(100+i);
//QueueUserWorkItem需要一個WaitCallback委托作為參數,該委托必須要一個object類型參數,如果我們需要傳遞參數,可以新建一個類。。
ThreadPool.QueueUserWorkItem(Mythread1.threadClass3);
}
Console.ReadLine();
}
2、同步的實現方式
上面說的都是異步的實現,事實上有時候我們也需要不同線程共享文件或者數據,這就需要保證一次只能一個線程訪問和改變共享的狀態,所以這就要用到同步技術
多線程同步技術有:
lock、Monitor(lock被編譯器解析為Monitor)、Mutex、Semaphore
比如:對於同一個對象,我遍歷出20個進程,都把該對象傳遞過去,對該對象的成員num做循環5000次加1操作,此時會出現的問題是,當第一個線程的i等於2000,判斷<5000可以進入循環體的時候,突然線程給了第二個線程,第二個線程繼續執行它上次在i=1的時候暫停的操作,這時i突然變成2000,相當於少加了1999次。。如果經常發生這種情況,最後的20個線程的總的結果必定小於10000。
Lock(鎖定)
private object o=new object
for(int i=0;i<5000;i++)
{
lock(object )
{
num++;
}
}
Monitor
private object o=new object
lock被編譯器解析為Monitor,Monitor調用Enter(object )方法,讓線程一直等待,直到當前線程被對象鎖定,才開始操作,當然不管是運行結束還是觸發異常,我們都必須調用Exit(object )方法,當然Monitor優於lock的地方在於他可以設置等待鎖定時間,即TryEnter方法
例如,設置讓線程等待500毫秒,如果發現還被其他線程鎖定,就返回lockif為false,
bool lockif=false;
Monitor.TryEnter(object,500,ref lockif);
if(lockif)
{
//執行操作
}
Mutex(互斥),互斥繼承WaitHandle(WaitHandle在異步委托的時候講過)
互斥和Monitor也很類似,也是確保只有一個進程被互斥鎖定,區別在於互斥可以跨越
多個進程(注意不是線程)來互斥同步,比如應用程序是否只能啟動一個,當然要達到這種效果必須為互斥命名,不命名的互斥不能跨進程。
Mutex mymutex = new Mutex(false,"myMutex",out
mutexif);
if (!mutexif)
{
//執行代碼
}
或者******************************
if (mymutex.WaitOne(50))
{
//終止線程50毫秒,直到該線程已經操作結束
//執行代碼
}
Semaphore(信號量),也繼承WaitHandle
信號量類似互斥鎖定Mutex,它是一種控制線程數量的互斥鎖定,首先
先定義一個信號量
var semaphore=new SemaphoreSlim(4,4);
然後遍歷20個進程,把semaphore作為參數傳到每一個進程執行的方法裡
SemaphoreSlim semaphore=o as SemaphoreSlim ;
Bool isCompleted=false;
While(!isCompleted)
{
//阻止當前進程,一直到他可以進入semaphore信號量內為止
if(semaphore..Wait(600))
{
try
{
}finally
{
semaphore.Release();//釋放一個信號量,當然也可以指定釋放幾個信號量參數
isCompleted=true;
}
}else
{
//4個信號量已經滿了,線程繼續等待
}
}