如何实现线程同步和互斥锁在C#中的应用?

如何实现线程同步和互斥锁在C#中的应用?

编码文章call10242025-01-26 18:25:2716A+A-

线程同步和互斥锁概述

在多线程编程中,线程同步和互斥锁用于协调多个线程对共享资源的访问,防止由于并发导致的数据不一致或资源竞争问题。

  • 线程同步: 确保多个线程按特定顺序或条件执行。
  • 互斥锁: 通过强制线程互斥访问共享资源,避免资源竞争。

C# 提供了多种机制实现线程同步和互斥锁。


线程同步和互斥锁的常见实现方式

1. 使用lock关键字

lock 是 C# 提供的一种简单实现互斥锁的方式,它基于 Monitor 类,可以防止多个线程同时访问共享资源。

代码示例:

using System;
using System.Threading;

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

    static void IncrementCounter()
    {
        for (int i = 0; i < 5; i++)
        {
            lock (lockObject)
            {
                counter++;
                Console.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId} incremented counter to {counter}");
            }
            Thread.Sleep(100);
        }
    }

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

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

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

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

优点:

  • 简单易用。
  • 自动释放锁,避免死锁。

2. 使用Monitor类

Monitor 类提供比 lock 更细粒度的控制,比如 TryEnter 方法可以指定等待时间。

代码示例:

using System;
using System.Threading;

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

    static void AccessResource()
    {
        if (Monitor.TryEnter(lockObject, TimeSpan.FromSeconds(1)))
        {
            try
            {
                Console.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId} is accessing the resource.");
                Thread.Sleep(500);
            }
            finally
            {
                Monitor.Exit(lockObject);
            }
        }
        else
        {
            Console.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId} could not acquire the lock.");
        }
    }

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

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

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

3. 使用Mutex类

Mutex 是一种系统级别的互斥锁,支持跨进程同步。

代码示例:

using System;
using System.Threading;

class Program
{
    private static Mutex mutex = new Mutex();

    static void AccessResource()
    {
        mutex.WaitOne(); // 获取互斥锁
        try
        {
            Console.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId} is accessing the resource.");
            Thread.Sleep(500);
        }
        finally
        {
            mutex.ReleaseMutex(); // 释放互斥锁
        }
    }

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

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

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

特点:

  • 可跨进程使用。
  • 性能较 lock 和 Monitor 略低。

4. 使用Semaphore和SemaphoreSlim

  • Semaphore: 限制多个线程访问资源,允许指定线程数。
  • SemaphoreSlim: 是 Semaphore 的轻量级版本,仅限于单进程。

代码示例:

using System;
using System.Threading;

class Program
{
    private static SemaphoreSlim semaphore = new SemaphoreSlim(2); // 允许最多 2 个线程同时访问

    static void AccessResource()
    {
        semaphore.Wait(); // 获取信号量
        try
        {
            Console.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId} is accessing the resource.");
            Thread.Sleep(1000);
        }
        finally
        {
            semaphore.Release(); // 释放信号量
        }
    }

    static void Main()
    {
        for (int i = 0; i < 5; i++)
        {
            new Thread(AccessResource).Start();
        }

        Console.ReadLine();
    }
}

特点:

  • 可用于控制并发访问数量。
  • SemaphoreSlim 更适合单进程场景。

5. 使用ReaderWriterLockSlim

ReaderWriterLockSlim 支持读写锁机制,允许多个线程同时读取,但只有一个线程可以写入。

代码示例:

using System;
using System.Threading;

class Program
{
    private static ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim();
    private static int sharedResource = 0;

    static void ReadResource()
    {
        rwLock.EnterReadLock();
        try
        {
            Console.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId} read the value: {sharedResource}");
        }
        finally
        {
            rwLock.ExitReadLock();
        }
    }

    static void WriteResource()
    {
        rwLock.EnterWriteLock();
        try
        {
            sharedResource++;
            Console.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId} wrote the value: {sharedResource}");
        }
        finally
        {
            rwLock.ExitWriteLock();
        }
    }

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

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

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

特点:

  • 提高读多写少场景的效率。
  • 更适用于数据读写冲突多的场景。

线程同步和互斥锁的比较

机制

特性

适用场景

lock

简单易用,仅限单进程,基于 Monitor 类

简单的互斥访问

Monitor

提供更细粒度的控制,支持超时等功能

高级互斥控制

Mutex

跨进程互斥,但性能稍低

跨进程的资源同步

Semaphore

控制线程并发数量,可跨进程

限制线程数量

SemaphoreSlim

轻量级版本,仅限单进程

限制线程数量(单进程)

ReaderWriterLockSlim

支持读写分离锁,读多写少时性能优异

数据读写冲突多的场景


总结

  • 在单进程场景中,lock 是首选,简单高效。
  • 对于跨进程同步,可以使用 Mutex 或 Semaphore。
  • 在需要限制并发数量时,使用 Semaphore 或 SemaphoreSlim。
  • 数据读多写少时,ReaderWriterLockSlim 是更好的选择。

根据场景合理选择同步机制,可以有效避免多线程编程中的竞态条件、数据不一致和死锁问题。

点击这里复制本文地址 以上内容由文彬编程网整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!
qrcode

文彬编程网 © All Rights Reserved.  蜀ICP备2024111239号-4