如何创建一个只在调用线程持有锁时运行的方法?

Nil*_*oCK 1 c# multithreading locking c#-3.0

在我下面的不安全类中,可以做些什么来阻止某人在没有获得锁定的情况下执行不安全的方法?

class Unsafe
{
    private static readonly object lockObj;

    void MethodA()
    {
        lock (lockObj)
        {
            // do some things
            DoUnsafeThing();
        }
    }

    void MethodB()
    {
        lock (lockObj)
        {
            // do some things
            DoUnsafeThing();
        }
    }

    void DoUnsafeThing()
    {
        if (callerHasLock)
            // Do the unsafe thing
        else
            return; // or throw some exception
    }
}
Run Code Online (Sandbox Code Playgroud)

再次获取锁定DoUnsafeThing()是一个选项:

void DoUnsafeThing()
{
    lock (lockObj)
    {
        // Do the unsafe thing
    }
}
Run Code Online (Sandbox Code Playgroud)

DoUnsafeThing()现在可以被尚未拥有锁的线程调用.

Mar*_* L. 5

您应该能够使用Monitor.IsEntered()来验证线程本身是否已获得锁:

void DoUnsafeThing()
{
    if (Monitor.IsEntered(lockObj))
        // Do the unsafe thing
    else
        return; // or throw some exception
}
Run Code Online (Sandbox Code Playgroud)

您可以使用Monitor该类来处理锁.在C#中,lock(...)语句只是语法糖Monitor.Enter(o); try {...} finally {Monitor.Exit(o);}.其中还有其他选项可用于微调.请记住,多线程很难.了解您的工具集.

编辑:(响应框架版本问题更新)

在.NET 4.5之前,AFAIK处理这个问题的唯一方法是在同步对象旁边使用线程静态布尔值,设置为true刚进入之后和false退出之前.同样的布尔 - 调用它callerHasLock,以符合上面的代码 - 然后可以在锁定上下文中测试,结果与之相同Monitor.IsEntered.

  • 您可以执行类似于Marc建议的操作,但使用3.5中的Monitor.TryEnter.一个线程应该能够锁定同一个对象两次. (2认同)