日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > C# >内容正文

C#

细说C#多线程那些事 - 线程同步和多线程优先级

發(fā)布時間:2024/9/20 C# 50 豆豆
生活随笔 收集整理的這篇文章主要介紹了 细说C#多线程那些事 - 线程同步和多线程优先级 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

上個文章分享了一些多線程的一些基礎(chǔ)的知識,今天我們繼續(xù)學(xué)習(xí)。

一、Task類

上次我們說了線程池,線程池的QueueUserWorkItem()方法發(fā)起一次異步的線程執(zhí)行很簡單

但是該方法最大的問題是沒有一個內(nèi)建的機(jī)制讓你知道操作什么時候完成,有沒有一個內(nèi)建的機(jī)制在操作完成后獲得一個返回值。為此,可以使用System.Threading.Tasks中的Task類。

Task類在命名空間System.Threading.Tasks下,通過Task的Factory返回TaskFactory類,以TaskFactory.StartNew(Action)方法可以創(chuàng)建一個新的異步線程,所創(chuàng)建的線程默認(rèn)為后臺線程,不會影響前臺UI窗口的運行。

如果要取消線程,可以利用CancellationTakenSource對象。如果要在取消任務(wù)后執(zhí)行一個回調(diào)方法,則可以使用Task的()方法。

簡單代碼實現(xiàn):

using System; using System.Threading.Tasks;namespace Threading {class Program{public static Int32 ThreadSum(Int32 n){Int32 sum = 0;for (; n > 0; --n)sum += n; return sum;}static void Main(string[] args){var t = new Task<Int32>(n => ThreadSum((Int32)n), 100);t.Start();var cwt = t.ContinueWith(task => Console.WriteLine("The result is {0}", t.Result));Console.ReadKey();}} } Task類示例代碼 using System; using System.Threading.Tasks;public class Example {public static void Main(){Task t = Task.Factory.StartNew( () => {int ctr = 0;for (ctr = 0; ctr <= 1000000; ctr++){}Console.WriteLine("Finished {0} loop iterations",ctr);} );t.Wait();} }

更多內(nèi)容參考: https://msdn.microsoft.com/zh-cn/library/system.threading.tasks.task.aspx

?

二、異步執(zhí)行

委托的異步執(zhí)行代碼:BeginInvoke() 和 EndInvoke()

using System;namespace Threading {public delegate string MyDelegate(object data);class Program{public static string Thread1(object data){return data.ToString();}public static void ThreadCallback(IAsyncResult data){Console.WriteLine("ThreadCallback = > " + data.AsyncState);}static void Main(string[] args){var mydelegate = new MyDelegate(Thread1);IAsyncResult result = mydelegate.BeginInvoke("Thread1 Para", ThreadCallback, "Callback Para");//異步執(zhí)行完成var resultstr = mydelegate.EndInvoke(result);Console.WriteLine(resultstr);Console.ReadKey();}} } 委托異步執(zhí)行示例代碼

三、線程同步

線程同步:指多個線程協(xié)同、協(xié)助、互相配合。一些敏感數(shù)據(jù)不允許被多個線程同時訪問,此時就使用同步訪問技術(shù),保證數(shù)據(jù)在任何時刻,最多有一個線程訪問,以保證數(shù)據(jù)的完整性。

1、互斥鎖lock()語句

同步訪問共享資源的首選技術(shù)是C#的 lock 關(guān)鍵字,lock 允許定義一段線程同步的代碼語句,它需要定義一個標(biāo)記(即一個對象引用),線程在進(jìn)入鎖定范圍的時候必須獲得這個標(biāo)記,在退出鎖定范圍時需要釋放鎖。當(dāng)試圖鎖定的是一個實例級的私有方法時,使用方法本身所在對象的引用就可以了。然而,如需鎖定公共成員中的一段代碼,比較安全的做法是聲明私有的object成員作為鎖標(biāo)識。

public class DemoClass {private readonly object threadLock = new object();public void Method(){// 使用鎖標(biāo)識lock (threadLock){//…… }} }

再來一個混合線程同步鎖的例子:

using System; using System.Threading;namespace Threading {public sealed class SimpleHybirdLock : IDisposable{//Int32由基元用戶模式構(gòu)造(Interlocked的方法)使用private Int32 m_waiters = 0;// AutoResetEvent是基元內(nèi)核模式構(gòu)造private AutoResetEvent m_waiterLock = new AutoResetEvent(false);public void Enter(){//指出這個線程想要獲得的鎖if (Interlocked.Increment(ref m_waiters) == 1)return; //鎖可以自由使用//另一個線程擁有鎖(發(fā)生競爭),使這個線程等待m_waiterLock.WaitOne(); //這里產(chǎn)生較大的性能//WaitOne 返回后,這個線程拿到鎖了 }public void Leave(){//這個線程準(zhǔn)備釋放鎖if (Interlocked.Increment(ref m_waiters) == 0)return; //沒有其他線程等待直接返回//有其他線程正在阻塞,喚醒其中一個m_waiterLock.Set(); //這里產(chǎn)生較大的性能//WaitOne 返回后,這個線程拿到鎖了 }public void Dispose(){m_waiterLock.Dispose();}} }

?

2、Monitor實現(xiàn)線程同步

通過Monitor.Enter() 和 Monitor.Exit()實現(xiàn)排它鎖的獲取和釋放,獲取之后獨占資源,不允許其他線程訪問。

還有一個TryEnter方法,請求不到資源時不會阻塞等待,可以設(shè)置超時時間,獲取不到直接返回false。

public class DemoClass {private readonly object threadLock = new object();public void Method(){Monitor.Enter(threadLock);try{//…… }finally{Monitor.Exit(threadLock);}} }

3、維護(hù)自由鎖(System.Threading.Interlocked)實現(xiàn)線程同步,Interlocked允許我們對數(shù)據(jù)進(jìn)行一些原子操作:CompareExchange(), Decrement(), Exchange(), Increment()。這些靜態(tài)方法需要以引用方式傳入變量。如:注意newVal 和 intVal 的值都是遞增之后的值。

4、[Synchronization]特性可以有效地使對象的所以實例的成員都保持線程安全。當(dāng)CLR分配帶[Synchronization]特性的對象時,它會把這個對象放在同步上下文中。這是編寫線程安全代碼的一種偷懶方式,因為它不需要我們實際深入線程控制敏感數(shù)據(jù)的細(xì)節(jié),但這種方式對性能有影響,因為即使一個方法沒有使用共享資源,CLR仍然會鎖定對該方法的調(diào)用。

5、系統(tǒng)內(nèi)置對象

互斥(Mutex), 信號量(Semaphore), 事件(AutoResetEvent/ManualResetEvent),線程池

https://www.onlinebuff.com/article_understand-monitor-vs-mutex-vs-semaphore-vs-semaphoreslim-onlinebuff_60.html

6、SpinLock

https://docs.microsoft.com/zh-cn/dotnet/standard/threading/how-to-use-spinlock-for-low-level-synchronization

7、輕量級信號量 CountdownEvent,SemaphoreSlim,ManualResetEventSlim

四、線程優(yōu)先級

系統(tǒng)會為每一個線程分配一個優(yōu)先級別。.NET線程優(yōu)先級,是指定一個線程的相對于其他線程的相對優(yōu)先級,它規(guī)定了線程的執(zhí)行順序,對于在CLR中創(chuàng)建的線程,其優(yōu)先級別默認(rèn)為Normal,而在CLR之外創(chuàng)建的線程進(jìn)入CLR時,將會保留其先前的優(yōu)先級,可以通過訪問線程的Priority屬性來獲取或設(shè)置線程的優(yōu)先級別。

System.Threading命名空間中的ThreadPriority枚舉定義了一組線程優(yōu)先級的所有可能值,我這里按級別由高到低排列出來常用的,具體的說明就不在這里解釋。

Highest ?, AboveNormal , ?Normal ?, ?BelowNormal , ?Lowest

除了這些還有Realtime,但Realtime優(yōu)先級盡量避免,他的優(yōu)先級相當(dāng)高,甚至?xí)蓴_操作系統(tǒng)的任務(wù),比如阻礙一些必要的磁盤I/O和網(wǎng)絡(luò)傳輸。也可能會造成不及時處理鍵盤和鼠標(biāo)的輸入,導(dǎo)致用戶會感覺死機(jī)了。

?

代碼示例:

using System; using System.Threading;namespace Threading {class Program{public static void Thread1(){for (int i = 0; i < 10; i++){Console.Write("1 ");}}public static void Thread2(){for (int i = 0; i < 10; i++){Console.Write("2 ");}}public static void Thread3(){for (int i = 0; i < 10; i++){Console.Write("3 ");}}public static void Thread4(){for (int i = 0; i < 10; i++){Console.Write("4 ");}}public static void Thread5(){for (int i = 0; i < 10; i++){Console.Write("5 ");}}static void Main(string[] args){var t1 = new Thread(Thread1);var t2 = new Thread(Thread2);var t3 = new Thread(Thread3);var t4 = new Thread(Thread4);var t5 = new Thread(Thread5);t1.Priority = ThreadPriority.Highest;t2.Priority = ThreadPriority.AboveNormal;t3.Priority = ThreadPriority.Normal;t4.Priority = ThreadPriority.BelowNormal;t5.Priority = ThreadPriority.Lowest;t1.Start();t2.Start();t3.Start();t4.Start();t5.Start();Console.ReadKey();}} }

運行結(jié)果:

?很明顯,根據(jù)線程的優(yōu)先級高低順序執(zhí)行的。

五、阻塞調(diào)用線程

Join阻塞調(diào)用線程,直到該線程終止。

using System; using System.Threading;namespace Threading {class Program{static void Main(string[] args){var threadStartA = new ThreadStart(delegate(){ for (int i = 0; i < 1000000; i++){if (i % 10000 == 0)Console.Write("A");}});var threadA = new Thread(threadStartA);var threadStartB = new ThreadStart(delegate(){ for (int i = 0; i < 500000; i++){if (i % 10000 == 0)Console.Write("B");}threadA.Join(); //阻塞線程threadB,插入threadA進(jìn)行執(zhí)行for (int i = 0; i < 500000; i++){if (i % 10000 == 0)Console.Write("B1");}});var threadB = new Thread(threadStartB);//啟動線程 threadA.Start();threadB.Start();Console.ReadKey();}} }

運行結(jié)果:

從運行結(jié)果可以看出:一開始,ThreadA和ThreadB交替執(zhí)行,當(dāng)ThreadB執(zhí)行到ThreadA.Join()方法時,ThreadB被阻塞,ThreadA插入進(jìn)來單獨執(zhí)行,當(dāng)ThreadA執(zhí)行完畢以后,ThreadB繼續(xù)執(zhí)行。

除了ThreadA和ThreadB外,程序中還有一個主線程(Main Thread)。現(xiàn)在我們在主線程中添加一些輸出代碼,看看主線程和工作線程A、B是如何并發(fā)運行的。

六、Parallel

這個類提供了For,Foreach,Invoke靜態(tài)方法。它內(nèi)部封裝了Task類。主要用于并行計算。

private void ParallelTest2(){for (int i = 1; i < 5; i++){Console.WriteLine(DoWork(i));}var plr = Parallel.For(1, 5, i => Console.WriteLine(DoWork(i)));}private int DoWork(int num){int sum = 0;for (int i = 0; i <= num; i++){sum += i;}return sum;}

?

//并行的for循環(huán)static void loop3(List<entityA> source){int count = source.Count();Parallel.For(0, count, item =>{//source[count].age= source[count].age + 10;System.Threading.Thread.Sleep(10);});}//并行的foreach循環(huán)static void loop4(List<entityA> source){Parallel.ForEach(source, item =>{item.age = item.age + 10;System.Threading.Thread.Sleep(10);});}

  

Parallel.ForEach<DataRow>(dt.Select(), row => { ..todo }

?

轉(zhuǎn)載于:https://www.cnblogs.com/yinrq/p/5419872.html

總結(jié)

以上是生活随笔為你收集整理的细说C#多线程那些事 - 线程同步和多线程优先级的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。