锁和互斥锁有什么区别?

163

锁(Lock)和互斥量(Mutex)有什么区别?为什么不能互换使用?

8个回答

181

锁定(Lock)是特定于应用程序域(AppDomain)的,而Mutex(互斥体)是特定于操作系统的,允许您执行进程间锁定和同步(IPC)。


115

lock 是编译器的关键字,而不是一个实际的类或对象。它是 Monitor 类功能的封装,旨在使 Monitor 更易于处理常见情况。

正如 Darin 所说,Monitor(和 lock 关键字)受限于 AppDomain。这主要是因为需要引用一个内存地址(以实例化对象的形式)来管理“锁定”,并维护 Monitor 的标识。

另一方面,Mutex 是 .Net 对操作系统构造的封装,可用于使用字符串 数据(而不是指向数据的指针)作为其标识符进行系统级别的同步。两个引用两个完全不同内存地址的两个字符串,但具有相同的 数据,实际上将利用同一个操作系统 Mutex。


61

Mutex可以是进程本地的,也可以是系统范围内的。MSDN:

互斥量有两种类型:本地互斥量,它们没有名称,以及命名系统互斥量。本地互斥量仅存在于您的进程中。

此外,在使用具有终端服务的系统上的系统范围互斥量时,需要特别注意 - 同一页上也详细介绍了这点。

Mutexlock之间的区别之一是Mutex利用kernel-level construct,因此同步始终需要至少一个用户空间-内核空间转换。

另一方面,lock - 实际上是Monitor的快捷方式,试图避免分配内核资源并转换到内核代码(因此更为简洁快速 - 如果必须找到它类似的WinAPI构造,则为CriticalSection)。

另一个区别是其他人指出的:命名Mutex可以在进程之间使用。

除非有特殊需求或需要跨进程同步,否则最好坚持使用lock(又称Monitor)。
还有几个“次要”的区别,例如如何处理放弃等等。
同样的情况也适用于3.5中的ReaderWriterLockReaderWriterLockSlim,以及.NET 4.0中的Semaphore和新的SemaphoreSlim
后者xxSlim类不能用作系统范围内的同步原语,但它们从来没有被设计成这样 - 它们“只是”旨在更快速、更节省资源。

33
我使用Mutex来检查是否已经在同一台机器上运行了应用程序的副本。
bool firstInstance;
Mutex mutex = new Mutex(false, @"Local\DASHBOARD_MAIN_APPLICATION", out firstInstance);

if (!firstInstance)
{
    //another copy of this application running 
}
else
{
    //run main application loop here.
}
// Refer to the mutex down here so garbage collection doesn't chuck it out.
GC.KeepAlive(mutex);

1
感谢您提供示例。 - themefield
如果你将互斥体的实例化分配给启动对象上的静态字段,那么你可能可以避免使用GC.KeepAlive(mutex) - Carter Canedy

10

已经有很多人谈论过这个话题了,但是为了简单起见,以下是我的看法。

lock -> 简单易用,对监视器的包装器,能够在一个应用程序域中锁定跨线程。

未命名互斥量 -> 类似于 lock,但是锁定范围更广,并且跨越了进程中的应用程序域。

命名互斥量 -> 锁定范围甚至比未命名互斥量还要广,可以跨越操作系统中的进程。

现在,选择最适合您情况的选项即可。


根据我从这里的答案和互斥锁示例中的理解 https://msdn.microsoft.com/en-us/library/system.threading.mutex(v=vs.110).aspx :无名互斥锁与锁的行为相同。然而,mutex.WaitOne(1000)给我们一个超时锁的机会。另一方面,Monitor.TryEnter也给了我们这个能力。正如所提到的,Mutex是一个包装器。因此,我会使用锁或监视器而不是无名互斥锁。但是,如果需要跨进程使用锁,则必须使用命名互斥锁。如果我错了,请纠正我。 - Koray

9

互斥锁是跨进程的,典型的例子就是确保一个应用程序只运行一个实例。

第二个例子是,假设你有一个文件,并且不希望不同的进程访问同一文件,那么你可以实现一个互斥锁。但是请记住,互斥锁是操作系统范围内的,不能在两个远程进程之间使用。

锁是保护代码部分最简单的方式,它是针对应用程序域的,如果你想要更精细的同步控制,可以将锁替换为监视器。


2

以下是未在答案中提到的一些较小的差异:

  1. In the case of using locks, you can be sure that the lock will be released when an exception happens inside the lock's block.
    That's because the lock uses monitors under the hood and is implemented this way:

     object __lockObj = x;
     bool __lockWasTaken = false;
     try
     {
         System.Threading.Monitor.Enter(__lockObj, ref __lockWasTaken);
         // Your code...
     }
     finally
     {
         if (__lockWasTaken) System.Threading.Monitor.Exit(__lockObj);
     }
    

    Thus, in any case, the lock is released, and you don't need to release it manually (like you'd do for the mutexes).

  2. For Locks, you usually use a private object to lock (and should use).
    This is done for many reasons. (More info: see this answer and official documentation).

因此,在锁的情况下,您不能(意外地获得)从外部访问锁定对象并造成损害。
但在Mutex的情况下,由于通常有一个被标记为公共并且可以从任何地方使用的Mutex,因此您可以这样做。


0

锁和监视器基本上用于为应用程序自身生成的线程即内部线程提供线程安全性。另一方面,互斥锁确保外部应用程序生成的线程即外部线程的线程安全性。使用互斥锁,任何时候只有一个外部线程可以访问我们的应用程序代码。

阅读此文


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接