在本文中,我们展示了如何使用Mutex原语来确保C#中的线程安全。
线程是程序的唯一执行路径。Thread
类表示C#中的线程。它创建并控制线程、设置其优先级并获取其状态。
死锁发生在一组线程共享相同的资源并且由于试图访问已被另一个线程锁定的资源而被彼此阻塞时。
互斥锁
为了确保线程安全,我们需要一个同步机制来授予对共享资源的访问权限。Mutex是一种同步原语,它只允许一个线程访问共享资源。其他想要访问资源的线程被阻塞,直到持有互斥体的线程释放它。
互斥量类似于锁,但它可以跨多个进程工作;也就是说,它可以是计算机范围的,也可以是应用程序范围的。Mutex
类位于System.Threading
命名空间中。
访问共享资源的代码段称为关键段或受保护段。资源可以是数据结构或设备。线程使用WaitOne
获取互斥量并使用ReleaseMutex
释放它。
C#互斥量简单例子
下面是一个使用Mutex的简单例子。
class Program { private static Mutex mutex = new Mutex(); private const int nThreads = 4; private static void Worker() { UseResource(); } private static void UseResource() { mutex.WaitOne(); string? name = Thread.CurrentThread.Name; Console.WriteLine($"{name} has entered protected section"); Thread.Sleep(800); Console.WriteLine($"{name} has left protected section"); mutex.ReleaseMutex(); } static void Main(string[] args) { for (int i = 0; i < nThreads; i++) { var t = new Thread(new ThreadStart(Worker)); t.Name = $"Thread {i + 1}"; t.Start(); } Console.Read(); } }
在程序中,我们创建了四个访问共享资源的线程。每个线程都可以独占访问资源。
private static Mutex mutex = new Mutex();
Mutex
是一个静态字段。
private static void Worker() { UseResource(); }
每个线程都调用这个worker。
private static void UseResource() { mutex.WaitOne(); string? name = Thread.CurrentThread.Name; Console.WriteLine($"{name} has entered protected section"); Thread.Sleep(800); Console.WriteLine($"{name} has left protected section"); mutex.ReleaseMutex(); }
这是使用WaitOne
和ReleaseMutex
方法受互斥锁保护的代码的关键部分。
for (int i = 0; i < nThreads; i++) { var t = new Thread(new ThreadStart(Worker)); t.Name = $"Thread {i + 1}"; t.Start(); }
在for循环中,我们生成四个线程。
Console.Read();
为确保所有线程都有时间完成,我们调用了Console.Read
方法。线程完成运行后,只需按回车键即可。
$ dotnet run Thread 1 has entered protected section Thread 1 has left protected section Thread 2 has entered protected section Thread 2 has left protected section Thread 3 has entered protected section Thread 3 has left protected section Thread 4 has entered protected section Thread 4 has left protected section
C#Mutex单实例
在下面的示例中,我们创建了一个单实例应用程序。计算机上只允许运行一个应用程序。
为了创建单实例应用程序,我们使用命名互斥文本。为了使互斥量适用于所有终端会话,互斥量的名称以Global\
为前缀。
public class Program { public static void Main() { using var mutex = new Mutex(false, @"Global\MySingletonApp"); bool IsRunning = !mutex.WaitOne(TimeSpan.Zero); if (IsRunning) { Console.WriteLine("application is already running"); return; } Console.WriteLine("application started"); Console.ReadKey(); mutex.ReleaseMutex(); } }
在程序中,我们创建了一个名为mutex的全局变量。这可以防止我们在一台计算机上创建多个应用程序实例。该程序的另一个实例只有在运行的应用程序完成后才能运行。
尝试在两个不同的终端中运行该应用程序。
在本文中,我们使用了Mutex原语来同步对C#中受保护资源的访问。
列出所有C#教程。