欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C# 線程同步詳解

 更新時(shí)間:2017年02月10日 11:37:11   作者:東秦男人  
本文主要介紹了C#中線程同步的相關(guān)知識(shí)。具有很好的參考價(jià)值,下面跟著小編一起來看下吧

前言

當(dāng)線程池的線程阻塞時(shí),線程池會(huì)創(chuàng)建額外的線程,而創(chuàng)建、銷毀和調(diào)度線程所需要相當(dāng)昂貴的內(nèi)存資源,另外,很多的開發(fā)人員看見自己程序的線程沒有做任何有用的事情時(shí)習(xí)慣創(chuàng)建更多的線程,為了構(gòu)建可伸縮、響應(yīng)靈敏的程序,我們?cè)谇懊娼榻B了C#異步編程詳解

但是異步編程同樣也存在著很嚴(yán)重的問題,如果兩個(gè)不同的線程訪問相同的變量和數(shù)據(jù),按照我們異步函數(shù)的實(shí)現(xiàn)方式,不可能存在兩個(gè)線程同時(shí)訪問相同的數(shù)據(jù),這個(gè)時(shí)候我們就需要線程同步。多個(gè)線程同時(shí)訪問共享數(shù)據(jù)的時(shí),線程同步能防止數(shù)據(jù)損壞,之所以強(qiáng)調(diào)同時(shí)這個(gè)概念,因?yàn)榫€程同步本質(zhì)就是計(jì)時(shí)問題。

異步和同步是相對(duì)的,同步就是順序執(zhí)行,執(zhí)行完一個(gè)再執(zhí)行下一個(gè),需要等待、協(xié)調(diào)運(yùn)行。異步就是彼此獨(dú)立,在等待某事件的過程中繼續(xù)做自己的事,不需要等待這一事件完成后再工作。線程就是實(shí)現(xiàn)異步的一個(gè)方式。異步是讓調(diào)用方法的主線程不需要同步等待另一線程的完成,從而可以讓主線程干其它的事情。

基元用戶模式和內(nèi)核模式構(gòu)造

基礎(chǔ)概念

基元:可以在代碼中使用的簡(jiǎn)單的構(gòu)造

用戶模式:通過特殊的CPU指令協(xié)調(diào)線程,操作系統(tǒng)永遠(yuǎn)檢測(cè)不到一個(gè)線程在基元用戶模式的構(gòu)造上阻塞。

內(nèi)核模式:由windows自身提供,在應(yīng)用程序的線程中調(diào)用由內(nèi)核實(shí)現(xiàn)的函數(shù)。

用戶模式構(gòu)造

易變構(gòu)造

C#編譯器、JIT編譯器和CPU都會(huì)對(duì)代碼進(jìn)行優(yōu)化,它們盡量保證保留我們的意圖,但是從多線程的角度出發(fā),我們的意圖并不一定會(huì)得到保留,下面舉例說明:

 static void Main(string[] args)
 {
 Console.WriteLine("讓worker函數(shù)運(yùn)行5s后停止");
 var t = new Thread(Worker);
 t.Start();
 Thread.Sleep(5000);
 stop = true;
 Console.ReadLine();
 }
 private static bool stop = false;
 private static void Worker(object obj)
 {
 int x = 0;
 while (!stop)
 {
 x++;
 }
 Console.WriteLine("worker函數(shù)停止x={0}",x);
 }
 

編譯器如果檢查到stop為false,就生成代碼來進(jìn)入一個(gè)無限循環(huán),并在循環(huán)中一直遞增x,所以優(yōu)化循環(huán)很快完成,但是編譯器只檢測(cè)stop一次,并不是每次都會(huì)檢測(cè)。

例子2---兩個(gè)線程同時(shí)訪問:

class test
 {
 private static int m_flag = 0;
 private static int m_value = 0;
 public static void Thread1(object obj)
 {
 m_value = 5;
 m_flag = 1;
 }
 public static void Thread2(object obj)
 {
 if (m_flag == 1)
 Console.WriteLine("m_value = {0}", m_value);
 }
 //多核CPU機(jī)器才會(huì)出現(xiàn)線程同步問題
 public void Exec()
 {
 var thread1 = new Thread(Thread1);
 var thread2 = new Thread(Thread2);
 thread1.Start();
 thread2.Start();
 Console.ReadLine();
 }
 }

程序在執(zhí)行的時(shí)候,編譯器必須將變量m_flag和m_value從RAM讀入CPU寄存器,RAM先傳遞m_value的值0,thread1把值變?yōu)?,但是thread2并不知道thread2仍然認(rèn)為值為0,這種問題一般來說發(fā)生在多核CPU的概率大一些,應(yīng)該CPU越多,多個(gè)線程同時(shí)訪問資源的幾率就越大。

關(guān)鍵字volatile,作用禁止C#編譯器、JTP編譯器和CPU執(zhí)行的一些優(yōu)化,如果做用于變量后,將不允許字段緩存到CPU的寄存器中,確保字段的讀寫都在RAM中進(jìn)行。

互鎖構(gòu)造

System.Threading.Interlocked類中的每個(gè)方法都執(zhí)行一次原子的讀取以及寫入操作,調(diào)用某個(gè)Interlocked方法之前的任何變量寫入都在這個(gè)Interlocked方法調(diào)用之前執(zhí)行,而調(diào)用之后的任何變量讀取都在這個(gè)調(diào)用之后讀取。

Interlocked方法主要是對(duì)INT32變量進(jìn)行靜態(tài)操作Add、Decrement、Compare、Exchange、CompareChange等方法,也接受object、Double等類型的參數(shù)。

原子操作:是指不會(huì)被線程調(diào)度機(jī)制打斷的操作;這種操作一旦開始,就一直運(yùn)行到結(jié)束,中間不會(huì)有任何 context switch (切換到另一個(gè)線程)。

代碼演示:

說明:通過Interlocked的方法異步查詢幾個(gè)web服務(wù)器,并同時(shí)返回?cái)?shù)據(jù),且結(jié)果只執(zhí)行一次。

//上報(bào)狀態(tài)類型
 enum CoordinationStatus
 {
 Cancel,
 Timeout,
 AllDone
 }
class AsyncCoordinator
 {
 //AllBegun 內(nèi)部調(diào)用JustEnded來遞減它
 private int _mOpCount = 1;
 //0=false,1=true
 private int _mStatusReported = 0;
 private Action<CoordinationStatus> _mCallback;
 private Timer _mTimer;
 //發(fā)起一個(gè)操作之前調(diào)用
 public void AboutToBegin(int opsToAdd = 1)
 {
 Interlocked.Add(ref _mOpCount, opsToAdd);
 }
 //處理好一個(gè)操作的結(jié)果之后調(diào)用
 public void JustEnded()
 {
 if (Interlocked.Decrement(ref _mOpCount) == 0)
 {
 ReportStatus(CoordinationStatus.AllDone);
 } 
 }
 //該方法必須在發(fā)起所有操作后調(diào)用
 public void AllBegin(Action<CoordinationStatus> callback, int timeout = Timeout.Infinite)
 {
 _mCallback = callback;
 if (timeout != Timeout.Infinite)
 {
 _mTimer = new Timer(TimeExpired, null, timeout, Timeout.Infinite);
 JustEnded();
 }
 }
 private void TimeExpired(object o)
 {
 ReportStatus(CoordinationStatus.Timeout);
 }
 public void Cancel()
 {
 ReportStatus(CoordinationStatus.Cancel);
 }
 private void ReportStatus(CoordinationStatus status)
 {
 //如果狀態(tài)從未報(bào)告過,就報(bào)告它,否則就忽略它,只調(diào)用一次
 if (Interlocked.Exchange(ref _mStatusReported, 1) == 0)
 {
 _mCallback(status);
 } 
 }
 }
class MultiWebRequest
 {
 //輔助類 用于協(xié)調(diào)所有的異步操作
 private AsyncCoordinator _mac = new AsyncCoordinator();
 protected Dictionary<string,object> _mServers = new Dictionary<string, object>
 {
 {"http://www.baidu.com",null},{"http://www.Microsoft.com",null},{"http://www.cctv.com",null},
 {"http://www.souhu.com",null},{"http://www.sina.com",null},{"http://www.tencent.com",null},
 {"http://www.youku.com",null}
 };
 private Stopwatch sp;
 public MultiWebRequest(int timeout = Timeout.Infinite)
 {
 sp = new Stopwatch();
 sp.Start();
 //通過異步方式一次性發(fā)起請(qǐng)求
 var httpclient = new HttpClient();
 foreach (var server in _mServers.Keys)
 {
 _mac.AboutToBegin(1);
 httpclient.GetByteArrayAsync(server).ContinueWith(task => ComputeResult(server, task));
 }
 _mac.AllBegin(AllDone,timeout);
 Console.WriteLine("");
 }
 private void ComputeResult(string server, Task<Byte[]> task)
 {
 object result;
 if (task.Exception != null)
 {
 result = task.Exception.InnerException;
 }
 else
 {
 //線程池處理IO
 result = task.Result.Length;
 }
 //保存返回結(jié)果的長(zhǎng)度
 _mServers[server] = result;
 _mac.JustEnded();
 }
 public void Cancel()
 {
 _mac.Cancel();
 }
 private void AllDone(CoordinationStatus status)
 {
 sp.Stop();
 Console.WriteLine("響應(yīng)耗時(shí)總計(jì){0}",sp.Elapsed);
 switch (status)
 {
 case CoordinationStatus.Cancel:
  Console.WriteLine("操作取消");
  break;
 case CoordinationStatus.AllDone:
  Console.WriteLine("操作完成,完成的結(jié)果如下");
  foreach (var server in _mServers)
  {
  Console.WriteLine("{0}",server.Key);
  object result = server.Value;
  if (result is Exception)
  {
  Console.WriteLine("錯(cuò)誤原因{0}",result.GetType().Name);
  }
  else
  {
  Console.WriteLine("返回字節(jié)數(shù)為:{0}",result);
  }
  }
  break;
 case CoordinationStatus.Timeout:
  Console.WriteLine("操作超時(shí)");
  break;
 default:
  throw new ArgumentOutOfRangeException("status", status, null);
 }
 }
 }

非常建議大家參考一下以上代碼,我在對(duì)服務(wù)器進(jìn)行訪問時(shí),也會(huì)常常參考這個(gè)模型。

簡(jiǎn)單的自旋鎖

class SomeResource
 {
 private SimpleSpinLock s1 = new SimpleSpinLock();
 public void AccessResource()
 {
 s1.Enter();
 //一次是有一個(gè)線程才能進(jìn)入訪問
 s1.Leave();
 }
 }
 class SimpleSpinLock
 {
 private int _mResourceInUse;
 public void Enter()
 {
 while (true)
 {
 if(Interlocked.Exchange(ref _mResourceInUse,1)==0)
  return;
 }
 }
 public void Leave()
 {
 Volatile.Write(ref _mResourceInUse,1);
 }
 }

這就是一個(gè)線程同步鎖的簡(jiǎn)單實(shí)現(xiàn),這種鎖的最大問題在于,存在競(jìng)爭(zhēng)的情況下會(huì)造成線程的“自旋”,這會(huì)浪費(fèi)CPU的寶貴時(shí)間,組織CPU做更多的工作,因此,這種自旋鎖應(yīng)該用于保護(hù)那些執(zhí)行的非??斓拇a。

以上就是本文的全部?jī)?nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來一定的幫助,同時(shí)也希望多多支持腳本之家!

相關(guān)文章

  • C#實(shí)現(xiàn)掃描槍掃描二維碼并打印(實(shí)例代碼)

    C#實(shí)現(xiàn)掃描槍掃描二維碼并打印(實(shí)例代碼)

    這篇文章主要介紹了C#實(shí)現(xiàn)掃描槍掃描二維碼并打印,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-01-01
  • C#中Abstract方法和Virtual方法的區(qū)別

    C#中Abstract方法和Virtual方法的區(qū)別

    這篇文章介紹了C#中Abstract方法和Virtual方法的區(qū)別,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-04-04
  • C#讀取數(shù)據(jù)庫返回泛型集合詳解(DataSetToList)

    C#讀取數(shù)據(jù)庫返回泛型集合詳解(DataSetToList)

    本篇文章主要是對(duì)C#讀取數(shù)據(jù)庫返回泛型集合(DataSetToList)進(jìn)行了介紹,需要的朋友可以過來參考下,希望對(duì)大家有所幫助
    2014-01-01
  • Unity實(shí)現(xiàn)簡(jiǎn)單場(chǎng)景分層移動(dòng)

    Unity實(shí)現(xiàn)簡(jiǎn)單場(chǎng)景分層移動(dòng)

    這篇文章主要為大家詳細(xì)介紹了Unity實(shí)現(xiàn)簡(jiǎn)單場(chǎng)景分層移動(dòng),分為前景、場(chǎng)景、背景等,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • 基于C#開發(fā)中的那些編碼問題(詳談)

    基于C#開發(fā)中的那些編碼問題(詳談)

    下面小編就為大家分享一篇基于C#開發(fā)中的那些編碼問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2017-11-11
  • C#檢查foreach判讀是否為null的方法

    C#檢查foreach判讀是否為null的方法

    這篇文章主要介紹了C#如何檢查foreach判讀其是否為null,文中給出了示例代碼,介紹的很詳細(xì),需要的朋友可以參考下方法
    2016-09-09
  • C#中使用split分割字符串的幾種方法小結(jié)

    C#中使用split分割字符串的幾種方法小結(jié)

    C#中使用split分割字符串的幾種方法,特整理下, 方便需要的朋友
    2013-03-03
  • C#自定義控件指示燈效果

    C#自定義控件指示燈效果

    在C#中實(shí)現(xiàn)一個(gè)指示燈控件,可以通過GDI+技術(shù)繪制,首先使用Pen對(duì)象繪制外環(huán),然后用SolidBrush對(duì)象填充內(nèi)圓,通過RectangleF定義繪制和填充的邊界,控件的屬性包括顏色、間隙、外環(huán)寬度等,本文給大家介紹C#自定義控件指示燈效果,感興趣的朋友跟隨小編一起看看吧
    2024-09-09
  • C#使用struct直接轉(zhuǎn)換下位機(jī)數(shù)據(jù)的示例代碼

    C#使用struct直接轉(zhuǎn)換下位機(jī)數(shù)據(jù)的示例代碼

    這篇文章主要介紹了C#使用struct直接轉(zhuǎn)換下位機(jī)數(shù)據(jù)的示例代碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-01-01
  • C#編程之事務(wù)用法

    C#編程之事務(wù)用法

    這篇文章主要介紹了C#編程之事務(wù)用法,結(jié)合實(shí)例形式對(duì)比分析了C#中事務(wù)提交與回滾的具體實(shí)現(xiàn)技巧與相關(guān)注意事項(xiàng),具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-11-11

最新評(píng)論