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

C# 線程同步的方法

 更新時間:2020年08月03日 11:49:28   作者:冬冬他哥哥  
這篇文章主要介紹了C# 線程同步的方法,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下

一、進(jìn)程內(nèi)部的線程同步

1、使用lock,用法如下:

private static readonly object SeqLock = new object();

    private void Print()
    {
      lock (SeqLock)
      {
        Console.WriteLine("test");
      }
    }

特性:只能傳遞對象,無法設(shè)置等待超時

2、使用:InterLocked(原子操作)

其在System.Threading命名空間下,Interlocked實際是類控制計數(shù)器,從而實現(xiàn)進(jìn)程的同步,其很容易實現(xiàn)生產(chǎn)者消費(fèi)者模型

//緩沖區(qū),只能容納一個字符
   private static char buffer;
   //標(biāo)識量(緩沖區(qū)中已使用的空間,初始值為0)
   private static long numberOfUsedSpace = 0;
   static void Main(string[] args)
   {
    //線程:寫入者
    Thread Writer = new Thread(delegate ()
    {
     string str = "這里面的字會一個一個讀取出來,一個都不會少,,,";
     for (int i = 0; i < 24; i++)
     {
      //寫入數(shù)據(jù)前檢查緩沖區(qū)是否已滿
      //如果已滿,就進(jìn)行等待,直到緩沖區(qū)中的數(shù)據(jù)被進(jìn)程Reader讀取為止
      while (Interlocked.Read(ref numberOfUsedSpace) == 1)
      {
       Thread.Sleep(50);
      }
      buffer = str[i]; //向緩沖區(qū)寫入數(shù)據(jù)
      //寫入數(shù)據(jù)后把緩沖區(qū)標(biāo)記為滿(由0變?yōu)?)
      Interlocked.Increment(ref numberOfUsedSpace);
     }
    });
    //線程:讀出者
    Thread Reader = new Thread(delegate ()
    {
     for (int i = 0; i < 24; i++)
     {
      //讀取數(shù)據(jù)前檢查緩沖區(qū)是否為空
      //如果為空,就進(jìn)行等待,直到進(jìn)程Writer向緩沖區(qū)中寫入數(shù)據(jù)為止
      while (Interlocked.Read(ref numberOfUsedSpace) == 0)
      {
       Thread.Sleep(50);
      }
      char ch = buffer;  //從緩沖區(qū)讀取數(shù)據(jù)
      Console.Write(ch);
      Interlocked.Decrement(ref numberOfUsedSpace);
     }
    });
    //啟動線程
    Writer.Start();
    Reader.Start();
    Console.ReadKey();

3、使用Monitor

其中Monitor.Enter()和lock相同

      Monitor.Enter(obj){
        //Synchronized part
      }finally{
        Monitor.Exit(obj);
      }

TryEnter則可設(shè)置等待時間等

bool lockTaken=false;
      Monitor.TryEnter(obj, 500, ref lockTaken);
      if(lockTaken){
        try
        {
          //Synchronized part
        }
        finally
        {
          Monitor.Exit(obj);
        }
      }else{
        //don't aquire the lock, excute other parts
      }

二、進(jìn)程間的同步

1. WaitHandle:

封裝等待對共享資源進(jìn)行獨(dú)占訪問的操作系統(tǒng)特定的對象。 WaitHandle:是一個抽象類,我們一般不直接用,而是用它的派生類:

AutoResetEvent、EventWaitHandle、ManualResetEvent、Mutex、Semaphore

這個抽象類的方法如下:

WaitOne(): 等待一個信號的出現(xiàn),可設(shè)置超時;

WaitAll(): 等待多個信號的出現(xiàn),可設(shè)置超時;

WaitAny(): 等待任意一個信號的出現(xiàn),可設(shè)置超時;

2、Mutex: 與Monitor 類似,只有一個線程能夠獲取鎖定。利用WaitOne() 獲取鎖定,利用ReleaseMutex() 解除鎖定。構(gòu)造函數(shù)使用如下:

      bool isNew = false;
      mutex = new Mutex(false, "Mutex1", out isNew);

參數(shù)1:鎖創(chuàng)建后是否由主調(diào)線程擁有。 如果設(shè)為true,相當(dāng)于調(diào)用了WaitOne(),需要釋放,否則其他線程無法獲取鎖;

參數(shù)2:鎖名稱,可通過OpenExist()或TryOpenExist() 打開已有鎖,因為操作系統(tǒng)識別有名稱的互鎖,所以可由不同的進(jìn)程共享。若鎖名稱為空,就是未命名的互鎖,不能在多個進(jìn)程之間共享;

參數(shù)3:  是否為新創(chuàng)建的互鎖;

下面的例子演示Mutex 在進(jìn)程之間的使用:    class Program

private static Mutex mutex = null; 
    static void Main(string[] args)
    {
      bool isNew = false;
      mutex = new Mutex(false, "Mutex1", out isNew);
      Console.WriteLine("Main Start....");
      mutex.WaitOne();
      Console.WriteLine("Aquire Lock and Running....");
      Thread.Sleep(10000);
      mutex.ReleaseMutex();
      Console.WriteLine("Release Lock....");
      Console.WriteLine("Main end....");
      Console.ReadLine();
    }
  }

連續(xù)2次運(yùn)行這個控制臺程序的exe,結(jié)果如下,首先運(yùn)行的獲取 Mutex1 互鎖, 后面運(yùn)行的會等待直到前面運(yùn)行的釋放 Mutex1 互鎖。

 3.Semaphore: 信號量的作用于互斥鎖類似,但它可以定義一定數(shù)量的線程同時使用。下面是構(gòu)造函數(shù):

      bool isNew = false;
      semaphore = new Semaphore(3, 3, "semaphore1", out isNew);

參數(shù)1:創(chuàng)建后,最初釋放的鎖的數(shù)量,如參數(shù)1設(shè)為2,參數(shù)2設(shè)為3,則創(chuàng)建后只有2個鎖可用,另1個已經(jīng)鎖定;

參數(shù)2:定義可用鎖的數(shù)量;

參數(shù)3:  信號量的名稱,與Mutex類似;

參數(shù)4:是否為新創(chuàng)建的互鎖;

以下例子創(chuàng)建了信號量“semaphore1”,利用Parallel.For() 同步運(yùn)行Func1() ,在Func1() 中,當(dāng)線程獲取信號量鎖,釋放鎖或等待超時,都會在控制臺里輸出,

class Program
  {
    private static Semaphore semaphore = null;
    static void Main(string[] args)
    {

      Console.WriteLine("Main Start....");
      bool isNew = false;
      semaphore = new Semaphore(3, 3, "semaphore1", out isNew);
      Parallel.For(0, 6, Func1);
      Console.WriteLine("Main end....");
      Console.ReadLine();
    }

    static void Func1(int index)
    {
      Console.WriteLine("Task {0} Start....",Task.CurrentId);
      bool isComplete = false;
      while (!isComplete)
      {
        if (semaphore.WaitOne(1000))  
        {
          try
          {
            Console.WriteLine("Task {0} aquire lock....", Task.CurrentId);
            Thread.Sleep(5000);
          }
          finally
          {
            semaphore.Release();
            Console.WriteLine("Task {0} release lock....", Task.CurrentId);
            isComplete = true;
          }
        }
        else
        {
          Console.WriteLine("Task {0} timeout....", Task.CurrentId);
        }
      }
    }

運(yùn)行結(jié)果如下,線程1,2,3首先獲取信號量鎖,線程4,5,6在等待,直到1,2,3釋放,

4. AutoResetEvent 類:

可以使用事件通知其他任務(wù),構(gòu)造函數(shù)為 public AutoResetEvent(bool initialState)。

當(dāng)initialState=true,處于signaled 模式(終止?fàn)顟B(tài)),調(diào)用waitone() 也不會阻塞任務(wù),等待信號,調(diào)用Reset()方法,可以設(shè)置為non-signaled 模式;

當(dāng)initialState=fasle,處于non-signaled 模式(非終止?fàn)顟B(tài)),調(diào)用waitone() 會等待信號阻塞當(dāng)前線程(可以在多個線程中調(diào)用,同時阻塞多個線程),直到調(diào)用set()發(fā)送信號釋放線程(調(diào)用一次,只能釋放一個線程),一般使用這種方式;

以下例子創(chuàng)建5個任務(wù),分別調(diào)用waitone()阻塞線程,接著每隔2s 調(diào)用set(),

private static AutoResetEvent autoReset = new AutoResetEvent(false);
    static void Main(string[] args)
    {
      Console.WriteLine("Main Start....");
      for (int i = 0; i < 5; i++)
      {
        Task.Factory.StartNew(() =>
        {
          Console.WriteLine("{0} Start....", Task.CurrentId);
          autoReset.WaitOne();
          Console.WriteLine("{0} Continue....", Task.CurrentId);
        });
      }
      for (int i = 0; i < 5;i++ )
      {
        Thread.Sleep(2000);
        autoReset.Set();
      }
      Console.WriteLine("Main end....");
      Console.ReadLine();
    }

運(yùn)行結(jié)果每次順序略有不同,釋放是隨機(jī)的:

5. ManualResetEvent 類:功能基本上和AutoSetEvent類似,但又一個不同點(diǎn):

使用AutoSetEvent,每次調(diào)用set(),切換到終止模式,只能釋放一個waitone(),便會自動切換到非終止模式;但ManualResetEvent,調(diào)用set(),切換到終止模式,可以釋放當(dāng)前所有的waitone(),需要手動調(diào)用reset()才能切換到非終止模式。

以下例子說明了這個不同的:

private static ManualResetEvent manualReset = new ManualResetEvent(false);
    static void Main(string[] args)
    {
      Console.WriteLine("Main Start....");
      for (int i = 0; i < 5; i++)
      {
        Task.Factory.StartNew(() =>
        {
          Console.WriteLine("{0} Start....", Task.CurrentId);
          manualReset.WaitOne();
          Console.WriteLine("{0} Continue....", Task.CurrentId);
        });
      }
      Thread.Sleep(2000);
      manualReset.Set();
      manualReset.WaitOne();
      Console.WriteLine("it doesn't work now, Main continue....");
      manualReset.Reset();
      manualReset.WaitOne();
      Console.WriteLine("Main end....");
      Console.ReadLine();
    }

以上就是C# 線程同步的方法的詳細(xì)內(nèi)容,更多關(guān)于c# 線程同步的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論