【发布时间】:2011-04-13 17:06:42
【问题描述】:
锁和互斥有什么区别?为什么不能互换使用?
【问题讨论】:
标签: c# multithreading synchronization
锁和互斥有什么区别?为什么不能互换使用?
【问题讨论】:
标签: c# multithreading synchronization
lock 是编译器关键字,而不是实际的类或对象。它是Monitor 类功能的包装器,旨在使Monitor 在常见情况下更易于使用。
正如达林所说,Monitor(和lock 关键字)仅限于AppDomain。主要是因为需要对内存地址的引用(以实例化对象的形式)来管理“锁”并维护Monitor 的标识
另一方面,Mutex 是围绕操作系统构造的 .Net 包装器,可用于系统范围的同步,使用字符串 data(而不是指向数据)作为其标识符。两个互斥锁引用两个完全不同的内存地址中的两个字符串,但具有相同的数据,实际上将使用相同的操作系统互斥锁。
【讨论】:
Mutex 可以是本地进程或系统范围。 MSDN:
互斥体有两种类型:未命名的本地互斥体和命名的系统互斥体。本地互斥体仅存在于您的进程中。
此外,在具有终端服务的系统上使用系统范围的互斥锁时,应特别小心 - 同一页面上也有详细说明。
Mutex 和lock 之间的区别之一是Mutex 使用kernel-level construct,因此同步始终需要至少一个用户空间-内核空间转换。
lock - 这实际上是Monitor class 的捷径,另一方面,它试图避免分配内核资源并转换到内核代码(因此更精简和更快 - 如果必须找到一个 WinAPI 构造类似,应该是CriticalSection)。
另一个区别是其他人指出的:命名 Mutex 可以跨进程使用。
除非有特殊需要或需要跨进程同步,否则最好坚持lock(又名Monitor)˛
还有其他几个“小”差异,例如如何处理放弃等。
对于 3.5 中的 ReaderWriterLock 和 ReaderWriterLockSlim、Semaphore 以及 .NET 4.0 中的新 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);
【讨论】:
Mutex 是一个跨进程,会有一个经典的例子,即不运行多个应用程序实例。
第二个例子是说你有一个文件,你不希望不同的进程访问同一个文件,你可以实现一个互斥锁,但记住一件事互斥锁是一个操作系统范围,不能在两个远程进程之间使用。
锁定是保护代码部分的最简单方法,它是特定于应用程序域的,如果您想要更受控的同步,可以将锁定替换为监控器。
【讨论】:
已经说了很多,但为了简单起见,这是我的看法。
lock -> 使用简单,封装在监视器上,跨 AppDomain 中的线程锁定。
未命名的互斥体 -> 类似于锁,只是锁定范围更大,并且它在一个进程中跨 AppDomain。
命名互斥体 -> 锁定范围比未命名的互斥体还要多,而且它在操作系统中是跨进程的。
所以现在选项已经存在,您需要选择最适合您情况的选项。
【讨论】:
答案中未提及的其他一些细微差异:
在使用锁的情况下,您可以确定当锁的块内发生异常时,锁将被释放。
那是因为锁在后台使用了监视器,并以this 方式实现:
object __lockObj = x;
bool __lockWasTaken = false;
try
{
System.Threading.Monitor.Enter(__lockObj, ref __lockWasTaken);
// Your code...
}
finally
{
if (__lockWasTaken) System.Threading.Monitor.Exit(__lockObj);
}
因此,在任何情况下,锁都会被释放,您无需手动释放它(就像您对互斥锁所做的那样)。
对于锁,您通常使用私有对象来锁定(并且应该使用)。
这样做有很多原因。 (更多信息:see this answer 和 official documentation)。
因此,如果出现锁,您无法(意外获得)从外部接触到锁定的对象并造成一些损坏。
但是对于 Mutex,您可以,因为通常有一个 Mutex 标记为 public 并且可以在任何地方使用。
【讨论】: