C#中Mutex的用法

38

我在 C# 中的线程方面有点新手,我的程序中我正在使用mutex来允许只有1个线程进入关键部分,但由于某种未知原因,在进行一些打印时,我可以看到多个线程正在进入我的关键部分,这是我的代码:

Mutex m = new Mutex();
m.WaitOne();
<C.S> // critical section here
m.ReleaseMutex();

我非常想知道我是否在这里犯了错误,提前感谢您的帮助。

编辑:

我的代码包括类,所以它基本上看起来更像这样:

public class test
{
    private mutex m;
    public test()
    {
         m = new mutex();
    }
    public func()
    {
         m.WaitOne();
         <C.S> // critical section here
         m.ReleaseMutex();
     }


    } 

你必须拥有该类的多个实例。 - Will Dean
3
这是一个实例级别的互斥锁;你确定你的代码没有在不相关的实例上进入了临界区吗?另外,任何错误都会导致代码永久锁定 - 你需要使用 try/finally 来确保安全。 - Marc Gravell
1
编辑后:此互斥锁仅在对象级别上工作,即1个CrticialSection /实例。这是您想要的吗? - H H
信息:Mutex互斥 - yu yang Jian
5个回答

68

这里的问题在于所有的调用者都在使用不同的互斥对象;你需要让锁对象共享,通常通过将其变为一个字段来实现。例如,使用更简单的lock比喻:

private readonly object syncLock = new object();
public void ThreadSafeMethod() {
    lock(syncLock) {
        /* critical code */
    }
}

或者使用互斥锁:

private readonly Mutex m = new Mutex();
public void ThreadSafeMethod() {
    m.WaitOne();
    try {
        /* critical code */
    } finally {
        m.ReleaseMutex();
    }
}

我正在使用的互斥锁是一个类的全局互斥锁,因此我认为它是同一个互斥锁。 - Nadav
1
@Nadav - 这不是你的问题所显示的内容... 你的问题显示它与代码相同的位置,即本地变量。 - Marc Gravell
2
Nadav - 你确定你没有多个类的实例吗?几乎所有“锁定/互斥”让多个调用通过的问题都是因为有比你预期的更多的锁定/互斥对象。 - Will Dean

5
该模式不进行任何锁定。每个线程都创建一个新的Mutex对象并立即拥有其锁。其他线程会创建并使用一个新的Mutex本身。 考虑使用常规lock()!
lock(_lockobject) {
   // do inside what needs to be done - executed on a single thread only
} 

其中_lockobject是您类中的一个简单私有变量:

private object _lockobject; 

编辑:感谢评论者的指正!存在某些情况下,lock(this)可能会产生危险。因此我已将其移除。


4
不要使用 lock(this)lock(someType) 或者 lock(anyString),这些都是不良的设计并且不够健壮。 - Marc Gravell
2
顺便说一句,锁定此对象并不总是一个好主意,最好创建一个简单的对象类型变量。http://www.toolazy.me.uk/template.php?content=lock%28this%29_causes_deadlocks.xml - VikciaR
2
lock(this) 不被认为是一个好的实践方式。(例如,参见http://haacked.com/archive/2006/08/08/ThreadingNeverLockThisRedux.aspx)。更好的方法是创建一个专门用于锁定的对象,并忘记任何对象都可以被锁定的.NET设计错误。 - Will Dean
1
@WillDean - 的确;我更希望有一个特定的类型,例如Monitor实例。此外,object应该是abstract;p - Marc Gravell

5

看起来你为每个线程提供了自己的互斥锁,这样做是不行的。

在大多数情况下,互斥锁是过度的。你只需要:

private static object syncLock = new object();  // just 1 instance

....

lock(syncLock)
{
    // critical section
}

2
我不确定从这个问题中我们能推断出是否有意使用 static...尽管我们也不能推断它不是;p - Marc Gravell
1
@Marc,正确。我使用static作为我认为是错误的相反面。代码并不完全清晰。 - H H

2

互斥锁用于标识运行应用程序实例。

 using (Mutex mutex = new Mutex(true, "app name", out createdNew))
            {
                if (createdNew)//check app is already run
                {
                    KillOthers();
                    StartApp();
                }
                else
                {
                    MessageBox.Show("Another instance already running!");
                }
            }

-2
我能否对被接受的答案进行更正?
private readonly Mutex m = new Mutex();
public void ThreadSafeMethod() {
    while(!m.WaitOne()){}
    try {
        /* critical code */
    } finally {
        m.ReleaseMutex();
    }
}

嗨,Emanuele。你为什么认为你的答案是一种改进呢?循环:while (!m.WaitOne()) { }永远不会运行超过一次,因为没有参数的WaitOne方法总是返回true(除非它从未返回)。 - Theodor Zoulias

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