程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C#線程同步的三類情形剖析

C#線程同步的三類情形剖析

編輯:C#入門知識

C#線程同步的三類情形剖析。本站提示廣大學習愛好者:(C#線程同步的三類情形剖析)文章只能為提供參考,不一定能成為您想要的結果。以下是C#線程同步的三類情形剖析正文


本文實例講述了C#線程同步的三類情形,分享給年夜家供年夜家參考。詳細剖析以下:

C# 曾經供給了我們幾種異常好用的類庫如 BackgroundWorker、Thread、Task等,借助它們,我們就可以夠分分鐘編寫出一個多線程的運用法式。

好比如許一個需求:有一個 Winform 窗體,點擊按鈕後,會將窗體中的數據導出到一個 output.pdf 文件中。本來的代碼沒有采取多線程技巧,所以當點擊按鈕後,全部窗體就釀成無呼應了。為懂得決這個成績,可使用 Task.Run(()=>{...導出文件的代碼});

下面的代碼看似簡略,卻隱蔽著各種危機。假如在導出的時代,窗體的數據被修正了,那會怎樣樣?假如多個窗體同時導出到統一個文件,又會怎樣樣?

在看完本系列後,你就會清晰了。

有點懂得的同伙都曉得線程同步有多種手腕,甚麼 mutex、moniter、seamphore、event 等等,我把它們歸為三類,對應三種須要線程同步的情形。

情形一:此茅坑有主了

當一個資本同時被多個線程拜訪時,有能夠會形成資本抵觸(特別是在存在多個寫線程的時刻)的情形。碰到這類情形,在 C# 中,我們可使用 Interlocked、lock、Moniter、SpinLock、ReadWriteLockSlim、Mutex 來處置成績。

甚麼情形下會被以為是情形一?

  當你設計的類中湧現靜態變量、IO操作時,就會碰到情形一。由於這些資本是由多個對象同享的,分歧的線程很同時去拜訪這些資本時,便可能會湧現爭用。

  當一個類被設計成單例,且包括實例變量時,也會碰到情形一。由於實例變量屬於這個單例,當多個線程把持此單例時,該變量能夠會被爭用。

  當一個類中的辦法挪用線程操作某個實例變量時,也會碰到情形一。

情形二:數目無限,先到先得

情形一強調的是一對多的情況,而在情形二中,資本的數目其實不獨一。比擬於情形一,情形二著重的是數目上的限制。而用於完成這一需求的類有:Semaphore、SemaphoreSlim。

甚麼情形下會被以為是情形二?

  當所操作的公共資本存在並發數限制的時刻(如數據庫銜接、IIS銜接數限制等),就被以為是情形二。

情形三:我讓你動,你能力動!

情形三存眷的是線程履行進程中的前後次序,而用於包管這類前後次序的方法就是經由過程線程通訊的方法:ManualResetEventSlim、ManualResetEvent、AutoResetEvent。

甚麼情形下會被以為是情形三?

當兩個線程所處置的工作有前後的依附時,好比線程二的履行進程依附線程一的履行成果,那就以為是情形三。

不限應用情形

下面的各類計劃其實不是相對只限於某一場景,好比 AutoResetEvent 便可以用於情形三,也能夠用於情形一。然則,殺雞焉用牛刀,固然應用 AutoResetEvent 可以或許完成情形一的需求,然則用不了 AutoResetEvent 的線程通訊才能,同時又會有一些額定的限制(每一個線程必需包管 wait 和 set 的成對應用,不然一個線程在鎖定資本後便可能被另外一個線程解鎖)。


    lock (m)
    {
        //....
    }
    
    //等價於以下方法
    autoResetEvent.WaitOne();
    //....
    autoResetEvent.Set();


  也有同伙說,可以用情形一中的 lock 計劃來完成情形三的需求。


    AutoResetEvent autoReset = new AutoResetEvent(false);
    private void button1_Click(object sender, EventArgs e)
    {     
        Task.Run(() =>
        {
            autoReset.WaitOne();
            Console.WriteLine("步調二");
        });
 
        Thread.Sleep(1000);//有意延遲從而包管第二個線程是在第一個線程以後才履行
        Task.Run(() =>
        {
            Console.WriteLine("步調一");
            autoReset.Set();
        });
    }

  下面這個例子終究輸入的成果可想而知。此實例解釋,不論線程現實的履行次序若何,AutoResetEvent 都能很輕易的包管兩個線程的履行次序。

假如用 lock 呢?
    private void button1_Click(object sender, EventArgs e)
    {
        Task.Run(() =>
        {
            lock (s)
            {
                Console.WriteLine("步調一");
            }
        });
 
        Thread.Sleep(1000);//必需工資確保步調二的線程要在步調一的線程以後履行
        Task.Run(() =>
        {
            lock (s)
            {
                Console.WriteLine("步調二");
            }
        });
    }

固然能完成,然則須要消費額定的代碼去工資包管兩個線程的履行次序。

若何在這麼多計劃中肯定終究所應用的,須要你能對項目標各類情形停止剖析,依據現實情形選擇對應的計劃,而不至於年夜材小用。

總 結

經由過程本系列文章的引見,信任能讓年夜家能對多線程中能夠碰著的情形有一個概念,不至於在面對多線程的時刻驚慌失措。

願望本文所述對年夜家的C#法式設計有所贊助。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved