<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      并發(fā)編程 - 線程同步(一)

      經(jīng)過前面對(duì)線程的嘗試使用,我們對(duì)線程的了解又進(jìn)一步加深了。今天我們繼續(xù)來深入學(xué)習(xí)線程的新知識(shí) —— 線程同步。

      01、什么是線程同步

      線程同步是指在多線程環(huán)境下,確保多個(gè)線程在同時(shí)使用共享資源時(shí)不會(huì)發(fā)生沖突或數(shù)據(jù)不一致問題的技術(shù),保證線程間的正確協(xié)作。它的目的是使得多個(gè)線程在執(zhí)行過程中能夠按照某種順序、安全地使用共享資源。

      02、為何需要線程同步

      1、避免競(jìng)爭(zhēng)條件

      不知道大家還記得在《并發(fā)編程 - 初識(shí)線程》中出現(xiàn)的關(guān)鍵字volatile和特性ThreadStatic嗎?它們都是為了解決多線程共享資源問題。

      在多線程中當(dāng)多個(gè)線程需要同時(shí)使用共享資源時(shí),很容易產(chǎn)生互相競(jìng)爭(zhēng)資源使用權(quán)的情況,這一問題也叫競(jìng)爭(zhēng)條件。此時(shí)就可以通過線程同步技術(shù)實(shí)現(xiàn)多個(gè)線程按順序使用共享資源,從而避免競(jìng)爭(zhēng)條件。

      2、保證共享資源安全

      我們舉個(gè)簡(jiǎn)單的例子,假如我的銀行賬戶里有1000元,此時(shí)我正在用電子銀行在線上操作準(zhǔn)備向我老婆的賬戶里轉(zhuǎn)賬100元,而恰巧此時(shí)我老婆拿著我的銀行卡準(zhǔn)備取款500。

      假如銀行系統(tǒng)還是一個(gè)只有多線程,沒有線程同步功能的老系統(tǒng),在這一前置條件下。假如恰巧我們倆在同一瞬間點(diǎn)了確認(rèn)操作,相信此時(shí)系統(tǒng)會(huì)發(fā)生什么?

      有可能會(huì)是系統(tǒng)同時(shí)收到我們倆的請(qǐng)求,此時(shí)我的操作線程A,首先讀取我賬戶余額1000,然后執(zhí)行轉(zhuǎn)賬操作把余額減100得到900,再更新至余額中。而我老婆的操作線程B因?yàn)槭呛臀彝瑫r(shí)的,所以在讀取我賬戶余額的時(shí)候得到的也是1000,而不是900,此時(shí)線程B執(zhí)行取款500操作把余額減500得到500,再更新至余額中。

      可以發(fā)現(xiàn)我們倆最后更新余額,無論誰更新成功最后結(jié)果都是不正確的。這個(gè)例子就導(dǎo)致銀行賬戶余額最終不正確,也就是我們說的共享資源不安全。如果使用線程同步,使得線程A、B可以按順序執(zhí)行,無論誰先執(zhí)行最終結(jié)果都會(huì)是正確的。

      下面我們?cè)賮斫Y(jié)合代碼舉一個(gè)經(jīng)典問題 —— torn read。

      先解釋一下什么叫torn read,可以翻譯成一次讀取被撕成兩半。或者說在機(jī)器級(jí)別上,要分兩個(gè)MOV指令才能讀完。

      具體來說就是一個(gè)long類型變量_var,當(dāng)一個(gè)線程把_var賦值為0x0123456789ABCDEF,而此時(shí)另一個(gè)線程來讀取_var,結(jié)果讀取的值是0x0123456700000000或0x0000000089ABCDEF。這同樣是因?yàn)槎嗑€程導(dǎo)致的共享資源不安全問題。

      下面看看模擬代碼實(shí)現(xiàn)效果:

      public class ThreadSync
      {
          //共享的int64變量
          public static long _var;  
          public static void Run()
          {
              //啟動(dòng)寫入線程
              var writerThread = new Thread(WriteToSharedValue);
              //啟動(dòng)讀取線程
              var readerThread = new Thread(ReadFromSharedValue);
              //啟動(dòng)線程
              writerThread.Start();
              readerThread.Start();
              //等待線程執(zhí)行完成
              writerThread.Join();
              readerThread.Join();
          }
          //寫入線程
          static void WriteToSharedValue()
          {
              //模擬分兩步寫入
              long high = 0x01234567;
              long low = 0x89ABCDEF;
              unsafe
              {
                  //將 _var 分成高低兩部分寫入
                  //寫高 32 位
                  _var = high << 32;
                  // 確保讀取線程能在這里讀取中間值
                  Thread.Sleep(0);  
                  //寫低 32 位
                  _var |= low;
              }
              Console.WriteLine($"寫: 寫入值 0x{_var:X16}");
          }
          //讀取線程
          static void ReadFromSharedValue()
          {
              // 讀取共享變量的值
              Console.WriteLine($"讀: 讀取值 0x{_var:X16}");
          }
      }
      

      我們看下執(zhí)行效果:

      當(dāng)然上面的例子并不是每次都會(huì)出現(xiàn)的,可能需要多運(yùn)行幾次,另外關(guān)于寫入線程為什么不是直接賦值而是把值拆成高低位分兩次寫入?

      這是因?yàn)槲业碾娔X是64位系統(tǒng),在大多數(shù)現(xiàn)代的 x64 系統(tǒng)架構(gòu)(例如 Intel 和 AMD 處理器)上,64 位的原子性操作通常是被保證的。即使對(duì)于像 long(64 位)這種數(shù)據(jù)類型,處理器通常會(huì)在硬件層面確保它的讀寫操作是原子性的,因此,不太容易發(fā)生撕裂的讀(torn read)。

      所以這里的代碼把一次賦值行為認(rèn)為拆解成兩步,同時(shí)Thread.Sleep(0)也為了讓當(dāng)前線程主動(dòng)讓出 CPU 時(shí)間片,使讀線程有機(jī)會(huì)讀取,使其更貼近在x32環(huán)境下運(yùn)行的情況。如果有條件可以用直接賦值再x32環(huán)境下看看效果。

      03、如何實(shí)現(xiàn)線程同步

      1、避免資源共享

      當(dāng)然嚴(yán)格意義上說可能這一條不算是線程同步,只能說解決了多線程碰到的問題,達(dá)到線程同步的效果。

      如果沒有共享資源,那么自然就無須進(jìn)行線程同步。大多數(shù)時(shí)候可以通過重新設(shè)計(jì)程序來除移共享狀態(tài),從而去掉復(fù)雜的同步構(gòu)造。盡可能避免在多個(gè)線程間使用單一對(duì)象。

      除了通過重新設(shè)計(jì)來移除共享狀態(tài),還可以通過語言特性設(shè)計(jì)使其達(dá)到無共享狀態(tài)。比如值類型在傳遞過程中總是被復(fù)制,每個(gè)線程都會(huì)有自己的數(shù)據(jù)副本,比如看下面這個(gè)方法:

      public static int Max(int val1, int val2)
      { 
          return val1 > val2 ? val1 : val2;
      }
      

      即使這個(gè)方法沒有使用任何線程同步方法,這個(gè)方法也是線程安全的。因?yàn)橹殿愋吞匦栽颍詡鹘oMax的兩個(gè)int值會(huì)復(fù)制到方法內(nèi)部,形成自己的數(shù)據(jù)副本。此時(shí)無論有多少個(gè)線程調(diào)用Max方法,每個(gè)線程處理的都是它自己的數(shù)據(jù),線程之間并不會(huì)互相干擾。

      2、用戶模式同步機(jī)制

      用戶模式同步機(jī)制指在用戶空間內(nèi)完成線程的阻塞和喚醒操作,由程序自己管理同步對(duì)象的一種同步方式,因?yàn)椴簧婕芭c操作系統(tǒng)內(nèi)核交換,因此開銷較低,更輕量級(jí)。

      實(shí)現(xiàn)方式有SpinLock、SpinWait、Monitor(lock)等。

      3、內(nèi)核模式同步機(jī)制

      內(nèi)核模式同步機(jī)制是指在操作系統(tǒng)內(nèi)核空間就完成線程的掛起與恢復(fù),由操作系統(tǒng)管理同步對(duì)象的一種同步方式,因?yàn)槊看尉€程同步操作都需要操作系統(tǒng)參與,因此必然回涉及內(nèi)核態(tài)的上下文切換,同時(shí)還是涉及到操作系統(tǒng)內(nèi)部的數(shù)據(jù)結(jié)構(gòu)和資源管理,因此內(nèi)核模式同步機(jī)制往往會(huì)導(dǎo)致較高的開銷。

      實(shí)現(xiàn)方式有Semaphore、Mutex、AutoResetEvent等。

      4、混合模式同步機(jī)制

      混合模式同步機(jī)制在某些情況下會(huì)根據(jù)線程競(jìng)爭(zhēng)的情況在用戶模式和內(nèi)核模式之間切換。通常,當(dāng)資源訪問沖突較小或線程阻塞較少時(shí),采用用戶模式同步;當(dāng)資源爭(zhēng)用較多或有較大的線程等待時(shí),自動(dòng)切換到內(nèi)核模式同步。

      實(shí)現(xiàn)方式有SemaphoreSlim、ManualResetEventSlim、CountDownEvent、Barrier、ReaderWriterLockSlim等。

      :測(cè)試方法代碼以及示例源碼都已經(jīng)上傳至代碼庫(kù),有興趣的可以看看。https://gitee.com/hugogoos/Planner

      posted @ 2025-01-23 21:52  IT規(guī)劃師  閱讀(1145)  評(píng)論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 2020国产欧洲精品网站| 色综合AV综合无码综合网站| 通化县| 亚洲综合国产激情另类一区| 成人乱码一区二区三区四区| 亚洲精品欧美综合二区| 欧美精品在线观看视频| 久久国产精品波多野结衣| 中文字幕在线亚洲精品| 乐至县| 中文字幕亚洲男人的天堂网络| 18禁成人免费无码网站| 久久狠狠高潮亚洲精品| 亚洲爆乳成av人在线视菜奈实| 色综合色综合综合综合综合| 暖暖 在线 日本 免费 中文| 在线中文字幕国产一区| 国产精品久久久国产盗摄| 最新国产AV最新国产在钱| 丰满爆乳一区二区三区| 国产一精品一av一免费爽爽| 亚洲国产一区二区三区四| 性欧美大战久久久久久久| 亚洲欧美在线观看品| 日本一本无道码日韩精品| 无码中文字幕热热久久| 久久天堂无码av网站| 精品一区二区三区四区激情| 2021av在线天堂网| 毛片亚洲AV无码精品国产午夜| 欧美成人无码a区视频在线观看 | 午夜大尺度福利视频一区| 亚洲熟女乱综合一区二区三区| 真人无码作爱免费视频| 老司机精品成人无码AV| 最新亚洲国产手机在线| 中文字幕日韩有码一区| 精品少妇无码一区二区三批| 成人无套少萝内射中出| 国产99在线 | 亚洲| 久久国产精品第一区二区|