C# 中的 Mutex(互斥体)基础用法

C# 中的 Mutex(互斥体)基础用法

在多线程编程中,互斥体(Mutex) 是一种用于同步线程访问共享资源的机制。它确保同一时间只有一个线程可以访问特定的资源,防止数据竞争和资源冲突。在 C# 中,System.Threading.Mutex 类提供了实现互斥体的功能。

目录

  1. 什么是 Mutex?
  2. Mutex 与其他同步机制的比较
  3. Mutex 的基本用法
  4. 命名 Mutex
  5. Mutex 的跨进程同步
  6. 使用 Mutex 的注意事项
  7. 示例代码
  8. 总结

1. 什么是 Mutex?

Mutex(Mutual Exclusion) 是一种同步原语,用于在多个线程或进程之间控制对共享资源的访问。Mutex 可以在同一进程内的多个线程之间同步,也可以在不同进程之间同步。

关键特点:

  • 互斥性:同一时间只能有一个线程持有 Mutex。
  • 跨进程同步:Mutex 可以在不同进程之间使用,这一点区别于 lock 关键字或 Monitor 类,这些仅限于同一进程内。

2. Mutex 与其他同步机制的比较

同步机制 跨进程 适用范围
lockMonitor 同一进程内的多线程
Mutex 跨进程或同一进程内的多线程
Semaphore 控制多个线程或进程对资源的访问
ReaderWriterLockSlim 高性能的读写锁,同一进程内

选择建议:

  • 如果只需要在同一进程内同步,且对性能有较高要求,推荐使用 lockMonitor)。
  • 如果需要跨进程同步,或者需要确保即使程序异常终止也能释放资源,选择 Mutex

3. Mutex 的基本用法

Mutex 的基本操作包括:

  • 创建 Mutex:实例化 Mutex 对象。
  • 获取 Mutex:通过调用 WaitOne 方法请求 Mutex。
  • 释放 Mutex:调用 ReleaseMutex 方法释放持有的 Mutex。

创建 Mutex

// 创建一个未命名的 Mutex,初始状态为未获取
Mutex mutex = new Mutex();

// 创建一个已命名的 Mutex,初始状态为未获取
Mutex mutex = new Mutex(false, "Global\\MyMutexName");

获取和释放 Mutex

try
{
    // 请求获取 Mutex
    mutex.WaitOne();

    // 访问受保护的资源
}
finally
{
    // 确保释放 Mutex
    mutex.ReleaseMutex();
}

4. 命名 Mutex

通过给 Mutex 指定名称,可以在不同的进程之间共享同一个 Mutex 实例。这对于需要跨进程同步的场景非常有用。

bool createdNew;
using (Mutex mutex = new Mutex(false, "Global\\MyNamedMutex", out createdNew))
{
    if (!createdNew)
    {
        Console.WriteLine("Mutex 已存在,可能已有另一个实例在运行。");
    }

    // 请求获取 Mutex
    mutex.WaitOne();

    try
    {
        // 执行需要同步的操作
    }
    finally
    {
        // 释放 Mutex
        mutex.ReleaseMutex();
    }
}

注意事项:

  • 命名时建议使用 Global\Local\ 前缀,以明确 Mutex 的作用范围。
  • 在 Windows 系统上,Global\ 适用于所有会话,Local\ 仅限当前会话。

5. Mutex 的跨进程同步

Mutex 不仅可以在同一进程内的多个线程之间同步,还可以在不同进程之间实现同步。这对于需要确保单一实例运行的应用程序非常有用。

示例场景:

  • 防止多个应用程序实例同时运行。
  • 不同应用程序之间协调对共享资源(如文件、数据库)的访问。

6. 使用 Mutex 的注意事项

  • 确保释放 Mutex:使用 try...finally 块确保在访问结束后释放 Mutex,避免死锁。
  • 避免长时间持有 Mutex:尽量缩短持有 Mutex 的时间,减少线程等待时间,提高性能。
  • 处理异常:在获取或释放 Mutex 时可能会抛出异常,需做好异常处理。
  • 命名唯一性:命名 Mutex 时确保名称的唯一性,避免与其他应用程序的 Mutex 冲突。

7. 示例代码

以下是一个简单的示例,演示如何使用 Mutex 在同一进程内的多个线程之间同步访问共享资源。

using System;
using System.Threading;

class Program
{
    // 创建一个命名的 Mutex
    static Mutex mutex = new Mutex(false, "Global\\MyMutexExample");

    static void Main(string[] args)
    {
        // 启动多个线程
        for (int i = 0; i < 5; i++)
        {
            Thread t = new Thread(new ThreadStart(AccessResource));
            t.Name = $"线程-{i + 1}";
            t.Start();
        }
    }

    static void AccessResource()
    {
        Console.WriteLine($"{Thread.CurrentThread.Name} 正在等待 Mutex...");

        // 请求获取 Mutex
        mutex.WaitOne();

        try
        {
            Console.WriteLine($"{Thread.CurrentThread.Name} 获得 Mutex。正在访问共享资源...");
            // 模拟访问共享资源
            Thread.Sleep(2000);
            Console.WriteLine($"{Thread.CurrentThread.Name} 访问完毕。");
        }
        finally
        {
            // 释放 Mutex
            mutex.ReleaseMutex();
            Console.WriteLine($"{Thread.CurrentThread.Name} 释放了 Mutex。");
        }
    }
}

输出示例:

线程-1 正在等待 Mutex...
线程-2 正在等待 Mutex...
线程-3 正在等待 Mutex...
线程-4 正在等待 Mutex...
线程-5 正在等待 Mutex...
线程-1 获得 Mutex。正在访问共享资源...
线程-1 访问完毕。
线程-1 释放了 Mutex。
线程-2 获得 Mutex。正在访问共享资源...
线程-2 访问完毕。
线程-2 释放了 Mutex。
...

8. 总结

Mutex 是 C# 中一个强大的同步工具,适用于需要在多线程甚至多进程之间协调对共享资源的访问的场景。通过合理使用 Mutex,可以有效避免数据竞争和资源冲突,提高应用程序的稳定性和可靠性。然而,由于 Mutex 的开销相对较大,且可能导致线程阻塞,因此在同一进程内进行简单的线程同步时,优先考虑使用 lockMonitor)等更轻量级的同步机制。

关键要点:

  • Mutex 可用于跨线程和跨进程同步。
  • 命名 Mutex 允许在不同进程之间共享同一个 Mutex 实例。
  • 使用 WaitOne 获取 Mutex,使用 ReleaseMutex 释放 Mutex。
  • 始终确保在 finally 块中释放 Mutex,避免死锁。
  • 适当选择同步机制,根据实际需求和性能要求做出权衡。

通过深入理解和正确使用 Mutex,可以有效地管理并发访问,确保程序的正确性和稳定性。

posted @ 2024-10-10 00:33  阿遇而已  阅读(123)  评论(0编辑  收藏  举报