当多个线程同时访问共享数据时,就会出现竞态条件(race condition)。这时候我们就需要使用“锁机制”(lock mechanism)来防止多个线程同时访问共享数据,保证线程安全性。其中一个经典的锁机制就是“排他锁”(exclusive lock),也称为“互斥锁”(mutex)。
下面是c#多线程中排他锁实现的攻略:
一、排他锁的概念
排他锁即互斥锁(mutex),是一种用于保护共享资源,防止在同一时间访问同一个资源的锁。基本原则是:在同一时间只允许一个线程访问共享资源。
二、c#中排他锁的实现
在c#中,排他锁由System.Threading.Mutex
类实现。该类提供了一个构造函数Mutex(bool initialValue)
和两个方法WaitOne()
和ReleaseMutex()
来实现互斥访问。
2.1 Mutex构造函数
Mutex(bool initialValue)
:创建一个Mutex实例,并且通过initialValue
参数指定初始值。initialValue
为true则当前线程拥有Mutex,否则Mutex为空闲状态。
示例代码:
Mutex mutex = new Mutex(false); //初始值为false
2.2 WaitOne()方法
WaitOne()
:线程试图获取Mutex,如果Mutex未被占用,该线程将拥有Mutex并进入运行状态。如果Mutex已被占用,则该线程将等待,直到其它线程释放Mutex。
示例代码:
mutex.WaitOne();
// 线程执行操作
mutex.ReleaseMutex();
2.3 ReleaseMutex()方法
ReleaseMutex()
:释放Mutex。
示例代码:
mutex.ReleaseMutex();
三、实例说明
3.1 简单实例
下面是一个简单的示例,展示Mutex的基本使用流程。
class MutexDemo
{
static Mutex mutex = new Mutex();
static void Main(string[] args)
{
for (int i = 0; i < 5; i++)
{
Thread t = new Thread(Print);
t.Start();
}
Console.ReadKey();
}
static void Print()
{
mutex.WaitOne();
Console.WriteLine($"线程{Thread.CurrentThread.ManagedThreadId}: 进入");
Thread.Sleep(1000);
Console.WriteLine($"线程{Thread.CurrentThread.ManagedThreadId}: 退出");
mutex.ReleaseMutex();
}
}
上面的代码中,我们创建了一个Mutex实例,然后创建了5个线程,在每个线程中调用WaitOne()
方法获取Mutex,执行一些操作,最后释放Mutex。
输出示例:
线程4: 进入
线程4: 退出
线程3: 进入
线程3: 退出
线程5: 进入
线程5: 退出
线程6: 进入
线程6: 退出
线程7: 进入
线程7: 退出
可以看出,每个线程都互斥地获取了Mutex,并且按照顺序执行,保证了线程安全性。
3.2 使用Mutex实现自旋锁
Mutex还可以用于实现自旋锁(spin lock),即不断检测共享资源是否可用,不可用则一直等待。这种锁适用于共享资源被持有的时间较短的场景。
下面是自旋锁示例代码:
class SpinLockDemo
{
static Mutex mutex = new Mutex();
static void Main(string[] args)
{
for (int i = 0; i < 5; i++)
{
Thread t = new Thread(SpinLock);
t.Start();
}
Console.ReadKey();
}
static void SpinLock()
{
bool lockTaken = false;
while (!lockTaken)
{
lockTaken = mutex.WaitOne(500);
if (!lockTaken)
Console.WriteLine($"线程{Thread.CurrentThread.ManagedThreadId}: 等待");
else
{
Console.WriteLine($"线程{Thread.CurrentThread.ManagedThreadId}: 进入");
Thread.Sleep(1000);
Console.WriteLine($"线程{Thread.CurrentThread.ManagedThreadId}: 退出");
mutex.ReleaseMutex();
}
}
}
}
上面的代码中,我们不断通过循环调用WaitOne()
方法检查Mutex是否可用。如果Mutex不可用,则线程进入等待状态;如果Mutex可用,则获取Mutex,并执行一些操作,最后释放Mutex。
输出示例:
线程4: 进入
线程4: 退出
线程3: 等待
线程5: 等待
线程6: 等待
线程7: 等待
线程3: 等待
线程5: 进入
线程5: 退出
线程6: 等待
线程7: 进入
线程7: 退出
线程6: 等待
线程3: 进入
线程3: 退出
可以看出,在Mutex被释放后,其它线程才有机会获取Mutex,保证了线程安全性。同时,Mutex的获取都是互斥的,保证了共享资源的一致性。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:c#多线程之间的排他锁的实现 - Python技术站