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

标签 c# asp.net-mvc multithreading asp.net-mvc-3

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

调用只会在 Controller 中完成,通常会有一两个锁定的代码块。

起初我想公开一些静态公共(public)对象并简单地使用它

lock(MyClass.lockObject)
{
 MyClass.doStuff();
 MyClass.doStuff2();
}

,但我发现它容易出错,因为我可能会忘记将它锁定在某个地方。我想知道在构造函数中使用 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.
    }
}

然后我可以将它用作:

using(MyClass myinstance = new MyClass())
{
    myInstance.doStuff();
    myInstance.doStuff2();
}

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

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

编辑:

扩展 Master Morality idea,这样会更好吗(我简化了一点,因为我只需要一个资源实例)?

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

最佳答案

恕我直言,最好在您自己的方法中锁定。这样,其他程序员或以后的您自己就不必记住在调用方法之前进行锁定,而且非常简单。

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

那天晚些时候...

var myClass = new MyClass();
myClass.DoSomething();

如果你想用一个锁调用多个方法,你可以用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();
    });

关于c# - 什么是锁定线程的正确方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11779376/

相关文章:

c++ - openmp parallel for with non-PODs

c# - 通过传递主键列表在Entity Framework中使用Find方法的多个记录

jquery - ASP.NET MVC2 和 JQuery 的高级最佳实践

c# - 在 MVC 4 中限制未登录用户对 Controller 操作的访问

c# - MVC 获取与发布

c# - TaskFactory,结束时开始一个新任务

c# - 面向对象编程中static修饰符有什么用?

c# - String.Format 和文化

c# - MEF 和 MVVM - 添加约定的方式?

c - 从 for 循环中向线程传递一个值