锁(Lock)和互斥量(Mutex)有什么区别?为什么不能互换使用?
lock
是编译器的关键字,而不是一个实际的类或对象。它是 Monitor
类功能的封装,旨在使 Monitor
更易于处理常见情况。
正如 Darin 所说,Monitor
(和 lock
关键字)受限于 AppDomain
。这主要是因为需要引用一个内存地址(以实例化对象的形式)来管理“锁定”,并维护 Monitor
的标识。
另一方面,Mutex
是 .Net 对操作系统构造的封装,可用于使用字符串 数据(而不是指向数据的指针)作为其标识符进行系统级别的同步。两个引用两个完全不同内存地址的两个字符串,但具有相同的 数据,实际上将利用同一个操作系统 Mutex。
Mutex
可以是进程本地的,也可以是系统范围内的。MSDN:
互斥量有两种类型:本地互斥量,它们没有名称,以及命名系统互斥量。本地互斥量仅存在于您的进程中。
此外,在使用具有终端服务的系统上的系统范围互斥量时,需要特别注意 - 同一页上也详细介绍了这点。
Mutex
和lock
之间的区别之一是Mutex
利用kernel-level construct,因此同步始终需要至少一个用户空间-内核空间转换。
另一方面,lock
- 实际上是Monitor
类的快捷方式,试图避免分配内核资源并转换到内核代码(因此更为简洁快速 - 如果必须找到它类似的WinAPI构造,则为CriticalSection
)。
另一个区别是其他人指出的:命名Mutex
可以在进程之间使用。
lock
(又称Monitor
)。ReaderWriterLock
和ReaderWriterLockSlim
,以及.NET 4.0中的Semaphore
和新的SemaphoreSlim
。xxSlim
类不能用作系统范围内的同步原语,但它们从来没有被设计成这样 - 它们“只是”旨在更快速、更节省资源。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);
已经有很多人谈论过这个话题了,但是为了简单起见,以下是我的看法。
lock -> 简单易用,对监视器的包装器,能够在一个应用程序域中锁定跨线程。
未命名互斥量 -> 类似于 lock,但是锁定范围更广,并且跨越了进程中的应用程序域。
命名互斥量 -> 锁定范围甚至比未命名互斥量还要广,可以跨越操作系统中的进程。
现在,选择最适合您情况的选项即可。
互斥锁是跨进程的,典型的例子就是确保一个应用程序只运行一个实例。
第二个例子是,假设你有一个文件,并且不希望不同的进程访问同一文件,那么你可以实现一个互斥锁。但是请记住,互斥锁是操作系统范围内的,不能在两个远程进程之间使用。
锁是保护代码部分最简单的方式,它是针对应用程序域的,如果你想要更精细的同步控制,可以将锁替换为监视器。
以下是未在答案中提到的一些较小的差异:
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).
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,因此您可以这样做。
锁和监视器基本上用于为应用程序自身生成的线程即内部线程提供线程安全性。另一方面,互斥锁确保外部应用程序生成的线程即外部线程的线程安全性。使用互斥锁,任何时候只有一个外部线程可以访问我们的应用程序代码。
GC.KeepAlive(mutex)
。 - Carter Canedy