C#中的自旋锁
在微信公众号上看到这篇文章,文章介绍了C#中的自旋锁,记录一下学习过程,以备后面复习要用。
1.概要
自旋锁是多线程同步机制,用于保护资源免受并发访问的影响。自旋锁的原理是:在多线程尝试获取锁时,他会不断的自旋(即一直循环检查锁是否可用),而不是立即进入休眠状态等待锁的释放。这种自旋的方式可以减少线程切换的开销,适用于短时间内锁的竞争情况。
2.基本原理
①自旋锁通常使用一个标志位(布尔值)来表示锁的状态。如果标志位为true,则表示锁被占用了。如果标志为false,表示所可用。
②当一个线程获取锁时,他会不断检查锁的状态。当检查到为false时,线程将获取到该锁,并且将其值设置为true,表示已经占用,线程进入临界区。
③当一个线程获取锁时,如果发现标志为true(锁以被其他线程占用),则该线程会在一个循环中自旋等待,直到锁被释放。
3.自旋锁的优缺点:
优点:
1.低延迟。自旋锁适用于短时间内的锁竞争情况。它不会让线程进入休眠状态,因此不会引入线程切换的开销,从而可以实现低延迟的锁操作。
2.预测性好。 自旋锁对线程的行为比较可控,因为它会一直自旋等待锁的释放。这使得线程的执行顺序更加可预测,适用于对实时性要求较高的应用场景。
3.避免死锁。自旋锁不会引入死锁,因为线程一直在自旋等待,不会形成循环等待的情况,只要其他线程释放了锁,等待的线程就能够继续执行。
缺点:
1.CPU资源浪费。自旋锁会占用CPU资源,因为等待锁的线程会一直自旋,不断地检查锁的状态。在锁竞争激烈或锁的持有时间较长时,可能会浪费大量的CPU时间。
2.不适用于长时间等待。 自旋锁适用于短时间内的锁竞争,但不适合用于长时间等待锁的场景。如果一个线程持有锁的时间较长,等待锁的线程会一直自旋,造成大量的CPU资源浪费。
3.可能导致饥饿。如果有多个线程在等待锁时,如果一个线程一直自旋,其他线程可能无法获得CPU时间片执行,导致饥饿现象。这需要合适的策略来解决。
C#还有其他实现线程同步的机制比如:Monitor(监视器)、Mutex(互斥量)、Semaphore(信号量)等。
自选锁的实现:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace SpinLockTest
{
internal class Program
{
// SpinLock:自旋锁类
private static SpinLock spinlock = new SpinLock();
static void Main(string[] args)
{
// 启动多个线程
for (int i = 0; i < 5; i++)
{
Thread thread = new Thread(DoWork);
thread.Start(i);
}
Console.WriteLine();
}
static void DoWork(object ThreadID)
{
bool lockToken = false;
try
{
// 尝试获取自旋锁
spinlock.Enter(ref lockToken);
Console.WriteLine($"Thread{ThreadID} Entered the C");
// 模拟临界区工作
Thread.Sleep(1000);
}
finally
{
if (lockToken)
{
// 释放自旋锁
spinlock.Exit();
Console.WriteLine($"Thread{ThreadID} Exit the C");
}
}
}
}
}
运行结果如下:
注明:如果有侵权,请联系删除。
欢迎大家一起学习交流。