代码改变世界

c#多线程互斥有哪些方法

  钟铧若岩  阅读(11)  评论(0编辑  收藏  举报
在 C# 多线程编程中,当多个线程访问共享资源时,可能会出现数据不一致或其他并发问题,这时就需要使用互斥机制来确保同一时间只有一个线程可以访问共享资源。以下是几种常见的 C# 多线程互斥方法:

1. lock 语句


lock 语句是 C# 中最常用的实现线程互斥的方式,它基于 Monitor 类实现,使用简单方便。
复制代码
using System;
using System.Threading;

class Program
{
    private static readonly object lockObject = new object();
    private static int sharedResource = 0;

    static void Main()
    {
        Thread t1 = new Thread(Increment);
        Thread t2 = new Thread(Increment);

        t1.Start();
        t2.Start();

        t1.Join();
        t2.Join();

        Console.WriteLine($"Shared resource value: {sharedResource}");
    }

    static void Increment()
    {
        for (int i = 0; i < 100000; i++)
        {
            lock (lockObject)
            {
                sharedResource++;
            }
        }
    }
}
复制代码

 

解释:

  • lockObject 是一个用于同步的对象,通常是一个私有静态的 object 类型实例。
  • lock 语句会获取 lockObject 的锁,如果锁已被其他线程持有,则当前线程会阻塞,直到锁被释放。
  • 在 lock 语句块内的代码是临界区,同一时间只有一个线程可以执行该代码块,从而保证了对 sharedResource 的安全访问。

2. Monitor 类


Monitor 类提供了更底层的线程同步机制,lock 语句实际上是 Monitor 类的语法糖。
复制代码
using System;
using System.Threading;

class Program
{
    private static readonly object monitorObject = new object();
    private static int sharedValue = 0;

    static void Main()
    {
        Thread t1 = new Thread(UpdateValue);
        Thread t2 = new Thread(UpdateValue);

        t1.Start();
        t2.Start();

        t1.Join();
        t2.Join();

        Console.WriteLine($"Shared value: {sharedValue}");
    }

    static void UpdateValue()
    {
        for (int i = 0; i < 100000; i++)
        {
            Monitor.Enter(monitorObject);
            try
            {
                sharedValue++;
            }
            finally
            {
                Monitor.Exit(monitorObject);
            }
        }
    }
}
复制代码
解释:

 

  • Monitor.Enter 方法用于获取指定对象的锁,如果锁已被其他线程持有,则当前线程会阻塞。
  • try-finally 块确保无论是否发生异常,Monitor.Exit 方法都会被调用,从而释放锁。

3. Mutex 类

 

Mutex(互斥体)是一种跨进程的同步原语,可用于在多个进程或线程之间实现互斥访问。
复制代码
using System;
using System.Threading;

class Program
{
    private static readonly Mutex mutex = new Mutex();
    private static int counter = 0;

    static void Main()
    {
        Thread t1 = new Thread(Count);
        Thread t2 = new Thread(Count);

        t1.Start();
        t2.Start();

        t1.Join();
        t2.Join();

        Console.WriteLine($"Counter value: {counter}");
    }

    static void Count()
    {
        for (int i = 0; i < 100000; i++)
        {
            mutex.WaitOne();
            try
            {
                counter++;
            }
            finally
            {
                mutex.ReleaseMutex();
            }
        }
    }
}
复制代码
解释:

 

  • mutex.WaitOne 方法用于请求获取互斥体的所有权,如果互斥体已被其他线程或进程持有,则当前线程会阻塞。
  • mutex.ReleaseMutex 方法用于释放互斥体的所有权,允许其他线程或进程获取该互斥体。

4. SemaphoreSlim 类

 

SemaphoreSlim 是一个轻量级的信号量,可用于限制同时访问共享资源的线程数量。当将最大计数设置为 1 时,它可以作为互斥锁使用。
复制代码
using System;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    private static readonly SemaphoreSlim semaphore = new SemaphoreSlim(1, 1);
    private static int sharedData = 0;

    static async Task Main()
    {
        Task t1 = Task.Run(UpdateData);
        Task t2 = Task.Run(UpdateData);

        await Task.WhenAll(t1, t2);

        Console.WriteLine($"Shared data value: {sharedData}");
    }

    static async Task UpdateData()
    {
        for (int i = 0; i < 100000; i++)
        {
            await semaphore.WaitAsync();
            try
            {
                sharedData++;
            }
            finally
            {
                semaphore.Release();
            }
        }
    }
}
复制代码
解释:

 

    • SemaphoreSlim 的构造函数第一个参数表示初始计数,第二个参数表示最大计数。当最大计数为 1 时,它就相当于一个互斥锁。
    • semaphore.WaitAsync 方法用于请求获取信号量,如果信号量计数为 0,则当前线程会等待。
    • semaphore.Release 方法用于释放信号量,将计数加 1。
 
 

 
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示