Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/328.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 什么是锁定线程的正确方法?_C#_Asp.net Mvc_Multithreading_Asp.net Mvc 3 - Fatal编程技术网

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

C# 什么是锁定线程的正确方法?,c#,asp.net-mvc,multithreading,asp.net-mvc-3,C#,Asp.net Mvc,Multithreading,Asp.net Mvc 3,在我的MVC3C应用程序中,我有一些静态对象,我希望一次只对一个请求可用。只能通过方法访问它,但我希望在调用它的方法之间保持锁 调用只能在控制器中完成,通常会有一个或两个锁定的代码块 起初,我想公开一些静态的公共对象,并像这样简单地使用它 lock(MyClass.lockObject) { MyClass.doStuff(); MyClass.doStuff2(); } ,但我发现它很容易出错,因为我可能忘记将它锁定在某个位置。我想知道在构造函数中使用Monitor.Enter(),在D

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

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

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

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#,有时会忽略某些方面,而且线程在以后的调试中从来都不容易,所以我想知道我是否走上了一条好的道路。这是实现我目标的正确方式吗

编辑:

扩展大师道德观念,这样会更好吗(我简化了一点,因为我只需要一个资源实例)

公共类MyClass
{
静态保护只读MyResourceType _myResourceStatic=new MyResourceType();
静态公共无效工作(操作)
{
锁(_myResource)
{
行动(新MyClass(_myResource));
}        
}
受保护的MyClass(MyResourceType myResource)
{
_myResource=myResource;
}
受保护的只读资源;
public void DoFirstThing(){…}
public void DoSecondThing(){…}
}
MyClass.DoWork(x=>
{
x、 第一件事();
//做无关的事
x、 DoSecondThing();
});

与使用监视器相比,锁定更简单,更不容易出错。直接进入和退出

从您的示例中不清楚要同步什么


监视不是一个好主意。请输入构造函数并退出Dispose。如果不能正确构造类,则必须处理c'tor中的所有异常并调用Exit。锁定一个实例是没有意义的——这本质上意味着锁定c'tor。您可能希望查看Synchronized属性;但我不认为这是真正的建议。

立即执行来自其他对象对静态对象的请求是否至关重要?如果让静态对象维护其自身工作的队列,则可以通过线程隔离实现互斥。在来自另一个对象的调用中,请求的工作被放置在队列上,而在一个单独的线程中,静态对象通过队列工作(不过请注意,需要对队列进行互斥访问!)执行请求


您可以在将工作添加到队列的方法中设置调用对象块,直到静态对象通知为止,也可以提供回调接口,以允许静态对象通知调用对象其工作已完成。

从您的示例中不清楚您正试图做什么。 作为良好的编程实践,最好让每个单独的方法获得锁,并在关键部分完成时释放锁。 在您的情况下,它将是:

void doStuff()
{
    if(isDisposed) throw new ObjectDisposedException();
    // do stuff here, etc.
    lock(_locker) { 
       // enter critical section here 
    }
    // continue to do other stuff
}

void doStuff2()
{
    if(isDisposed) throw new ObjectDisposedException();
    // do stuff here, etc.
    lock(_locker) { 
       // enter critical section here 
    }
    // continue to do other stuff
}
现在,lock是使用Monitor类的捷径版本。实际上是这样翻译的:

bool getLock = false;
try {
  Monitor.Enter(locker, ref getLock);
  // do stuff here
}
finally {
  if(getLock) {
    Monitor.Exit(locker);
  }
}
这将使您能够更好地控制对象和内部表示的状态,
如果发生了错误,您可以恢复到对象的先前状态。

我认为最好在您自己的方法中锁定
。这样,另一个程序员,或者你以后的程序员,在调用一个方法之前,就不必记得
锁定
,这很简单

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, 为了安全起见,将其包装在一个helper类中

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();
    });
公共类MyClass
{
公共MyResourceType MyResource{get;set;}
public void DoFirstThing(){…}
public void DoSecondThing(){…}
}
公共类MyClassHelper
{
私有静态只读对象_gate=new object();
私有静态MyResourceType MyResource=新的MyResourceType();
私有MyClass_MyClass=新MyClass();
公共无效工作(行动)
{
锁(门)
{
_myClass.MyResource=MyResource;
行动(_myClass);
_myClass.MyResource=null;
}
}
}
...
var myClassHelper=新的myClassHelper();
myClassHelper.DoWork(x=>
{
x、 第一件事();
x、 DoSecondThing();
});

如果调用组合不多,可以将dostuff和doStuff2设置为私有,并在类中放置一个带锁的包装函数

static public void doStuffs()
{
    lock (lockObject)
    {
        doStuff();
        doStuff2();
    }
}

“但我希望在整个请求过程中保持锁”-这不会导致您的站点一次只能处理一个请求(一次至少有一个请求访问此静态对象)?抱歉,这是一种夸张;我的意思是,我希望它被锁定在方法调用之间,更长的请求将在开始时锁定,并且在完成处理时更精确地确定范围。我不确定你能保证所有相关的代码(控制器、视图、ActionFilters)都会在同一个线程上运行。好吧,当我现在想到它时,每个请求将只有一到两个代码块,它们必须锁定,我可以假设它们只会在控制器中。那么“保持在调用之间”呢适用于那些区块之间的区域?你在核心问题上仍然很模糊,构造器中没有逻辑;正如我所说的,这些方法也可能是静态的。构造函数和Dipose只需要在这里放一个例子。是的,我同意,但正如我所说的,我希望同时为两个方法保留锁,例如,我不希望
static public void doStuffs()
{
    lock (lockObject)
    {
        doStuff();
        doStuff2();
    }
}