C# 中的互斥鎖
互斥鎖是 C# 中使用的同步原語,用于控制多個線程或進程對共享資源的訪問。其目的是確保在任何給定時間只有一個線程或進程可以獲取互斥鎖,從而提供互斥。
C# 中互斥鎖的優點
可以使用互斥鎖 (Mutex) 并享受其帶來的好處。
1. 共享資源的獨占訪問
- 場景:多個線程或進程需要獨占訪問共享資源(例如文件、數據庫或硬件設備)的情況。
- 示例:考慮一個多線程應用程序,其中多個線程需要同時寫入共享日志文件。
- 好處: 利用互斥鎖,可以保證一次只有一個線程或進程可以訪問資源,從而防止數據損壞或競爭條件。
2.跨進程同步
- 場景:不同進程中運行的線程之間需要同步。
- 示例:協調多個進程對共享內存映射文件的訪問。
- 好處:互斥鎖可以被命名并在整個系統范圍內使用,從而實現跨進程邊界的同步。
3. 關鍵部分保護
- 場景:代碼的關鍵部分需要防止被多個線程并發執行的情況。
- 示例:考慮一個緩存實現,其中添加或刪除項目必須是線程安全的。
- 好處:通過使用互斥鎖,它有助于對關鍵部分的訪問進行序列化,確保一次只有一個線程執行受保護的代碼,從而避免競爭條件。
4. 資源池化
- 場景:管理對有限資源池(例如數據庫連接或網絡套接字)的訪問時。
- 示例:多個線程競爭可用連接的連接池。
- 好處:可以使用互斥鎖 (Mutex) 來控制對池的訪問,從而保證同時使用的用戶數量不超過池的容量。
5.避免死鎖
- 場景:在多個同步原語一起使用以防止發生死鎖的情況下。
- 示例:實現一個需要原子鎖定多個資源的事務系統。
- 好處:互斥鎖可以參與死鎖避免策略,有助于防止死鎖情況的發生。
互斥鎖的實現
步驟1.
使用Xaml View測試所有情況。
<Window x:Class="MutexExample.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:MutexExample"mc:Ignorable="d"Title="MainWindow" Height="450" Width="800"><Grid><StackPanel Orientation="Vertical"><Button x:Name="BtnSR" Height="30" Content="Shared Resource" Margin="10" Click="BtnSR_Click"/><Button x:Name="BtnCPS" Height="30" Content="Cross-Process Synchronization" Margin="10" Click="BtnCPS_Click"/><Button x:Name="BtnCSP" Height="30" Content="Critical Section Protection" Margin="10" Click="BtnCSP_Click"/><Button x:Name="BtnRP" Height="30" Content="Resource Pooling" Margin="10" Click="BtnRP_Click"/><Button x:Name="BtnDLA" Height="30" Content="Deadlock Avoidance" Margin="10" Click="BtnDLA_Click"/></StackPanel></Grid>
</Window>
后端編程
using System;
using System.Threading;
using System.Windows;namespace MutexExample
{public partial class MainWindow : Window{Mutex mutex = new Mutex();static int availableResources = 3;public MainWindow(){InitializeComponent();}private void SharedResourceAccess(object id){mutex.WaitOne(); // Acquire the mutextry{Console.WriteLine($"Thread {id} is accessing the shared resource...");// Simulate some workThread.Sleep(2000);}finally{mutex.ReleaseMutex(); // Release the mutex}}private void BtnSR_Click(object sender, RoutedEventArgs e){// Create multiple threads accessing the shared resourcefor (int i = 0; i < 5; i++){Thread thread = new Thread(SharedResourceAccess);thread.Start(i);}}private void BtnCPS_Click(object sender, RoutedEventArgs e){// Acquire the mutexif (mutex.WaitOne(TimeSpan.FromSeconds(5))){try{Console.WriteLine("Process 1 has acquired the mutex.");Console.ReadLine(); // Hold the mutex until Enter is pressed}finally{mutex.ReleaseMutex(); // Release the mutex}}else{Console.WriteLine("Process 1 failed to acquire the mutex.");}}private void CriticalSectionAccess(object id){mutex.WaitOne(); // Acquire the mutextry{Console.WriteLine($"Thread {id} is executing the critical section...");// Simulate some workThread.Sleep(2000);}finally{mutex.ReleaseMutex(); // Release the mutex}}private void BtnCSP_Click(object sender, RoutedEventArgs e){// Create multiple threads accessing a critical sectionfor (int i = 0; i < 5; i++){Thread thread = new Thread(CriticalSectionAccess);thread.Start(i);}}private void ResourceAccess(object id){mutex.WaitOne(); // Acquire the mutextry{if (availableResources > 0){availableResources--;Console.WriteLine($"Thread {id} acquired a resource. Remaining resources: {availableResources}");// Simulate some workThread.Sleep(2000);availableResources++;}else{Console.WriteLine($"Thread {id} could not acquire a resource. No resources available.");}}finally{mutex.ReleaseMutex(); // Release the mutex}}private void BtnRP_Click(object sender, RoutedEventArgs e){// Create multiple threads to access the resource poolfor (int i = 0; i < 5; i++){Thread thread = new Thread(ResourceAccess);thread.Start(i);}}private void BtnDLA_Click(object sender, RoutedEventArgs e){Thread thread1 = new Thread(Thread1);Thread thread2 = new Thread(Thread2);thread1.Start();thread2.Start();thread1.Join();thread2.Join();}private Mutex mutex1 = new Mutex();private Mutex mutex2 = new Mutex();private void Thread1(){mutex1.WaitOne();Console.WriteLine("Thread 1 acquired mutex1");Thread.Sleep(1000);mutex2.WaitOne();Console.WriteLine("Thread 1 acquired mutex2");mutex2.ReleaseMutex();mutex1.ReleaseMutex();}private void Thread2(){mutex2.WaitOne();Console.WriteLine("Thread 2 acquired mutex2");Thread.Sleep(1000);mutex1.WaitOne();Console.WriteLine("Thread 2 acquired mutex1");mutex1.ReleaseMutex();mutex2.ReleaseMutex();}}
}