锁和互斥锁有啥区别?

Posted

技术标签:

【中文标题】锁和互斥锁有啥区别?【英文标题】:What is the difference between lock and Mutex?锁和互斥锁有什么区别? 【发布时间】:2011-04-13 17:06:42 【问题描述】:

锁和互斥有什么区别?为什么不能互换使用?

【问题讨论】:

【参考方案1】:

lock 专用于 AppDomain,而Mutex 专用于操作系统,允许您执行进程间锁定和同步 (IPC)。

【讨论】:

【参考方案2】:

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

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

另一方面,Mutex 是围绕操作系统构造的 .Net 包装器,可用于系统范围的同步,使用字符串 data(而不是指向数据)作为其标识符。两个互斥锁引用两个完全不同的内存地址中的两个字符串,但具有相同的数据,实际上将使用相同的操作系统互斥锁。

【讨论】:

【参考方案3】:

Mutex 可以是本地进程或系统范围。 MSDN:

互斥体有两种类型:未命名的本地互斥体和命名的系统互斥体。本地互斥体仅存在于您的进程中。

此外,在具有终端服务的系统上使用系统范围的互斥锁时,应特别小心 - 同一页面上也有详细说明。

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

lock - 这实际上是Monitor class 的捷径,另一方面,它试图避免分配内核资源并转换到内核代码(因此更精简和更快 - 如果必须找到一个 WinAPI 构造类似,应该是CriticalSection)。

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

除非有特殊需要或需要跨进程同步,否则最好坚持lock(又名Monitor)˛

还有其他几个“小”差异,例如如何处理放弃等。

对于 3.5 中的 ReaderWriterLockReaderWriterLockSlimSemaphore 以及 .NET 4.0 中的新 SemaphoreSlim 等也可以这样说。 确实,后者 xxSlim 类不能用作系统范围的同步原语,但它们从来没有打算这样做——它们“只是”意味着更快和更资源友好。

【讨论】:

【参考方案4】:

我使用互斥锁来检查我是否已经在同一台机器上运行了应用程序的副本。

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);

【讨论】:

感谢您提供示例。【参考方案5】:

Mutex 是一个跨进程,会有一个经典的例子,即不运行多个应用程序实例。

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

锁定是保护代码部分的最简单方法,它是特定于应用程序域的,如果您想要更受控的同步,可以将锁定替换为监控器。

【讨论】:

【参考方案6】:

已经说了很多,但为了简单起见,这是我的看法。

lock -> 使用简单,封装在监视器上,跨 AppDomain 中的线程锁定。

未命名的互斥体 -> 类似于锁,只是锁定范围更大,并且它在一个进程中跨 AppDomain。

命名互斥体 -> 锁定范围比未命名的互斥体还要多,而且它在操作系统中是跨进程的。

所以现在选项已经存在,您需要选择最适合您情况的选项。

【讨论】:

正如我从答案和此处的互斥锁示例中了解到的那样 msdn.microsoft.com/en-us/library/… :未命名的互斥锁的作用与锁相同。然而 mutex.WaitOne(1000) 给了我们一个超时锁的机会。另一方面,Monitor.TryEnter 也为我们提供了这种能力。如前所述,Mutex 是一个包装器。所以我会使用锁或监视器而不是未命名的互斥锁。但是,如果需要跨进程锁定,则可以使用命名互斥锁。如果我错了,请纠正我。【参考方案7】:

答案中未提及的其他一些细微差异:

    在使用锁的情况下,您可以确定当锁的块内发生异常时,锁将被释放。 那是因为锁在后台使用了监视器,并以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 并且可以在任何地方使用。

【讨论】:

以上是关于锁和互斥锁有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

在队列的关键部分使用二进制信号量而不是互斥锁有啥优势吗?

独占锁和共享锁有啥区别?

linux下信号量和互斥锁的区别

多线程的同步和互斥有啥区别

信号量,互斥锁,读写锁和条件变量的区别

自旋锁和互斥锁的区别