C#線程鎖(自旋鎖SpinLock、互斥鎖Mutex、混合鎖Monitor | lock)

一、自旋鎖

自旋鎖是指當一個線程在獲取鎖對象的時候,如果鎖已經被其它線程獲取,那麼這個線程將會循環等待,不斷的去獲取鎖,直到獲取到了鎖。適合於原子操作時間非常短的場景

優點:避免了線程上下文切換。性能較高。

缺點:如果長時間等待,將消耗大量的CPU資源。而且多個等待中的線程,並不是等待時間越長就先獲取到鎖,可能會一直等待下去。

兩種實現方式如下:

實現代碼一:

private static int _SpinLock = 0;//鎖對象
private static int incrValue = 0;//共享資源
private void Run()
{
    //獲取鎖
    //使用int原子操作將_SpinLock的值賦值爲1,Interlocked.Exchange(ref _SpinLock, 1)的返回值爲改變之前的值。
    //如果返回0,則獲取到了鎖, 如果返回1,則鎖被佔用
    while (Interlocked.Exchange(ref _SpinLock, 1) != 0)
    {
        Thread.SpinWait(1);//自旋鎖等待
    }

    incrValue++;  //安全的邏輯計算

    //釋放鎖:將_SpinLock重置會0;
    Interlocked.Exchange(ref _SpinLock, 0);
}

[HttpGet]
public async Task<string> Get()
{
    Parallel.For(0, 1000, (i) =>
    {
        Run();
    });

    Console.WriteLine($"incrValue={incrValue}");
}

實現代碼二:

private static SpinLock _spinLock = new SpinLock();
private static int incrValue = 0;//共享資源
private void Run()
{
    bool locked = false;
    _spinLock.Enter(ref locked);//獲取鎖

    incrValue++;  //安全的邏輯計算

    if (locked) //釋放鎖
        _spinLock.Exit();
}
[HttpGet]
public async Task<string> Get()
{
    Parallel.For(0, 1000, (i) =>
    {
        Run();
    });

    Console.WriteLine($"incrValue={incrValue}");
}

 

二、互斥鎖

互斥鎖是基於原子操作和線程調度實現的;當一個線程在獲取鎖對象的時候,如果鎖已經被其它線程獲取,那麼這個線程不會循環獲取鎖,它會進入等待狀態,等待被喚醒。適用於等待時間較長和跨進程的場景。

互斥鎖支持重入(當一個線程獲取到鎖之後,中間的代碼可以再次獲取鎖。適用於多個函數調用。獲取鎖的次數必須等於釋放鎖的次數)。

互斥鎖支持跨進程共享;多個進程之間使用同一個互斥鎖。

實現代碼如下:

private static readonly Mutex _mutexLock = new Mutex();
private static int incrValue = 0;//共享資源
private void Run()
{
    _mutexLock.WaitOne();//獲取鎖
    try
    {
        incrValue++;  //安全的邏輯計算
    }
    finally {
        _mutexLock.ReleaseMutex();//釋放鎖
    }
}

[HttpGet]
public async Task<string> Get()
{

    Parallel.For(0, 1000, (i) =>
    {
        Run();
    });

    Console.WriteLine($"incrValue={incrValue}");
}

 

三、混合鎖

混合鎖混合了自旋鎖和互斥鎖。剛開始會像自旋鎖一樣,先重試一定的次數;超過這個次數之後將線程設置爲等待狀態。

混合鎖適用於大多數場景。

實現代碼一:

 private static readonly object _monitorLock = new object();
 private static int incrValue = 0;//共享資源
 private void Run()
 {
     var islocked = false;
     try
     {
         Monitor.Enter(_monitorLock, ref islocked);  //獲取鎖

         incrValue++;  //安全的邏輯計算
     }
     finally {
       if(islocked) Monitor.Exit(_monitorLock);// 釋放鎖
     }
 }

 [HttpGet]
 public async Task<string> Get()
 {
     Parallel.For(0, 1000, (i) =>
     {
         Run();
     });

     Console.WriteLine($"incrValue={incrValue}");
}

實現代碼二:

private static readonly object _monitorLock = new object();
private static int incrValue = 0;//共享資源
private void Run()
{
    lock (_monitorLock)
    {
        incrValue++;  //安全的邏輯計算
    }
}

[HttpGet]
public async Task<string> Get()
{
    Parallel.For(0, 1000, (i) =>
    {
        Run();
    });

    Console.WriteLine($"incrValue={incrValue}");
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章