锁定线程的正确方法是什么?

tra*_*kos 5 c# asp.net-mvc multithreading asp.net-mvc-3

在我的 MVC 3 C# 应用程序中,我有一些静态对象,我希望一次可用于一个请求。只能通过方法访问它,但我希望在调用其方法之间保持锁定。

调用仅在控制器中完成,通常会有一两个锁定的代码块。

起初我想公开一些静态公共对象并像这样使用它

lock(MyClass.lockObject)
{
 MyClass.doStuff();
 MyClass.doStuff2();
}
Run Code Online (Sandbox Code Playgroud)

,但我发现它很容易出错,因为我可能会忘记将其锁定在某个地方。Monitor.Enter()我想知道在构造函数和Dispose 方法中使用它是否是正确的方法Monitor.Exit(),然后将我的方法更改为非静态?比如说:

public class MyClass:IDisposable
{
    static protected object _locker = new object();
    protected bool isDisposed = false;

    public MyClass()
    {
        Monitor.Enter(_locker);
    }

    public void Dispose()
    {
        if (!isDisposed)
        {
            Monitor.Exit(_locker);
            GC.SuppressFinalize(this);
            isDisposed = true;
        }
    }

    ~SPInstances()
    {
        Dispose();
    }

    public void doStuff()
    {
        if(isDisposed) throw new ObjectDisposedException();
        // do stuff here, etc.
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我可以将它用作:

using(MyClass myinstance = new MyClass())
{
    myInstance.doStuff();
    myInstance.doStuff2();
}
Run Code Online (Sandbox Code Playgroud)

然后,即使我忘记在 using 中包装代码,它仍然会锁定,并且有可能在垃圾收集期间解锁......

我不精通 C#,有时会忽略某些方面,而且线程以后很难调试,所以我想知道我是否走在正确的轨道上。这是实现我的目标的正确方法吗?

编辑:

扩展大师道德的想法,这种方式会更好吗(我简化了一点,因为我只需要一个资源实例)?

public class MyClass
{
    static protected readonly MyResourceType _myResourceStatic = new MyResourceType();
    static public void DoWork(Action<MyClass> action)
    {
        lock(_myResource)
        {
            action(new MyClass(_myResource));
        }        
    }

    protected MyClass(MyResourceType myResource)
    {
        _myResource = myResource;
    }
    protected readonly _myResource;

    public void DoFirstThing() { ... }
    public void DoSecondThing(){ ... }
}

MyClass.DoWork(x => 
{
    x.DoFirstThing();
    // do unrelated stuff
    x.DoSecondThing();
});
Run Code Online (Sandbox Code Playgroud)

Mas*_*ity 3

恕我直言,最好lock采用您自己的方法。lock这样,其他程序员或您自己就不必在调用方法之前记住,而且这很简单。

public class MyClass
{
    private static readonly object _gate = new object();

    /* something that can only be accessed by one thread at a time...*/
    private static MyResourceType MyResource = new MyResourceType();

    public void DoSomething()
    {
         lock(_gate)
         {
            /* do something with MyResource, just make sure you
               DO NOT call another method that locks the gate
               i.e. this.DoSomethingElse(), in those situations,
               you can take the logic from DoSomethingElse() and
               toss it in a private method i.e. _DoSomethingElse().
             */
         }
    }

    private void _DoSomethingElse()
    {
        /* do something else */
    }

    public void DoSomethingElse()
    {
         lock(_gate)
         {
             _DoSomethingElse();
         }
     }
}
Run Code Online (Sandbox Code Playgroud)

那天晚些时候...

var myClass = new MyClass();
myClass.DoSomething();
Run Code Online (Sandbox Code Playgroud)

如果您希望能够使用锁调用多个方法,您可以使用 lambda 来实现,并且为了真正安全,请将其包装在辅助类中。

public class MyClass
{
    public MyResourceType MyResource { get; set; }
    public void DoFirstThing() { ... }
    public void DoSecondThing(){ ... }
}

public class MyClassHelper
{
    private static readonly object _gate = new Object();
    private static MyResourceType MyResource = new MyResourceType();

    private MyClass _myClass = new MyClass();        

    public void DoWork(Action<MyClass> action)
    {
         lock(_gate)
         {
             _myClass.MyResource = MyResource;
             action(_myClass);
             _myClass.MyResource = null;
         }
    }
}

...

var myClassHelper = new MyClassHelper();
myClassHelper.DoWork(x => 
    {
        x.DoFirstThing();
        x.DoSecondThing();
    });
Run Code Online (Sandbox Code Playgroud)