锁用于不同的方法

时间:2012-11-15 11:27:33

标签: c# locking

我有一个关于锁定的问题以及我是否正确行事。

在一个类中,我有一个静态锁对象,它在几个方法中使用,假设访问修饰符设置得恰当,我不会列出它们以保持简洁。

class Foo
{ 
   static readonly object MyLock = new object();

   void MethodOne()
   {
       lock(MyLock) { 
          // Dostuff
       }
   }

   void MethodTwo()
   {
       lock(MyLock) { 
          // Dostuff
       }
   }
}

现在,按照我理解的方式,锁定一次只保证一个线程能够获取它并进入一个方法的DoStuff()部分。

但同一个线程是否可以同时调用MethodOne()和MethodTwo()?这意味着他使用了他为这两种方法获得的锁?

我的预期功能是此类中的每个方法只能由单个线程调用,而此类中没有其他方法当前正在执行。

基础用法是一个数据库类,我只想要一个入口和出口点。它使用SQL Compact,因此如果我尝试读取受保护的数据,我会收到各种各样的内存错误。

让我简单地说,数据库中每隔一段时间发生一次内存异常,我不知道它来自哪里。我认为这是因为一个线程在完成任务之前对数据库做了很多事情,但是这段代码看起来应该像它应该的那样。

4 个答案:

答案 0 :(得分:2)

  

但同一个线程是否可以同时调用MethodOne()和MethodTwo()?

没有。相同的线程不能同时调用这两个方法,无论是否使用lock

lock(MyLock) 

可以理解如下:

MyLock对象有一个键进入自己。一个访问它的线程(比如t1)首先得到它。其他线程必须等到t1释放它。但t1可以调用另一个方法,并且会传递此行,因为它已经获得锁定。

但是,同时调用两种方法......单线程不可能。不在当前的编程世界中。

  

我理解它的方式,一个锁只保证一次只有一个线程能够抓住它并进入一个方法的DoStuff()部分。

您的理解是正确的,但请记住,线程用于执行并行执行,但线程内的执行始终是顺序的。

答案 1 :(得分:1)

  

但同一个线程是否可以同时调用MethodOne()和MethodTwo()?

单个线程无法同时调用任何

在多线程应用程序中,可能会发生这种情况 - 可以同时调用方法,但// Dostuff部分只能按顺序访问。

  

我的预期功能是此类中的每个方法只能由单个线程调用,而此类中没有其他方法当前正在执行。

然后不要在你的应用程序中使用额外的线程 - 只需使用主线程,不要使用额外的线程。

答案 2 :(得分:1)

正在运行Dostuff的{​​{1}}内线程调用MethodOne的唯一方法是MethodTwo的{​​{1}}拨打电话Dostuff。如果没有发生这种情况(即“互锁”组中的方法不相互呼叫),那么您就是安全的。

答案 3 :(得分:0)

这里可以回答一些问题。

  

但同一个线程是否可以调用MethodOne()和   MethodTwo()同时?意思是他使用了他拥有的锁   得到这两种方法?

不,一个线程有一个程序计数器,它位于MethodOne()MethodTwo()。但是,如果您有以下内容,

public void MethodThree()
{
    lock (MyLock)
    {
        MethodOne();
        MethodTwo();
    }
}

那也行,一个线程可以多次获得相同的锁。请注意你正在做的事情,因为随着代码变得更加复杂,你很容易陷入僵局。

  

我的预期功能是此类中的每个方法都只能   由单个线程调用,而此类中没有其他方法   目前正在执行。

     

基础用法是我只想要的数据库类   单一进入和退出点。它使用SQL Compact,所以如果我尝试   读取受保护的数据我得到各种各样的内存错误。

我真的不明白为什么,但是如果你认为你需要这样做是因为你使用的是SqlCompact,那你就错了。您应该使用transactions在SqlCe上支持

E.g。

using (var connection = new SqlCeConnection())
using (var command = new SqlCeCommand())
using (var transaction = conn.BeginTransaction())
{
    command.Transaction = transaction;
    command.ExecuteNonQuery();
    transaction.Commit();
}