lock()语句会阻塞进程/ appdomain中的所有线程吗?

时间:2010-06-08 12:58:15

标签: c# asp.net multithreading

也许问题听起来很愚蠢,但我不明白'关于线程和锁定的问题,我想得到确认(here's why I ask)。

因此,如果我同时拥有10台服务器和10台请求来到每台服务器,那么整个服务器场就有100条请求。没有锁定,那就是100请求数据库。

如果我这样做:

private static readonly object myLockHolder = new object();
if (Cache[key] == null)
{
   lock(myLockHolder)
   {
      if (Cache[key] == null)
      {
         Cache[key] = LengthyDatabaseCall();
      }
   }
}

我会做多少个数据库请求? 10? 100?或者我有线程?

6 个答案:

答案 0 :(得分:11)

您有一个对象层次结构:

  • 您有服务器(10)
  • 在每台服务器上,您都有进程(可能只有1 - 您的服务/应用程序池)
  • 在每个流程中,您都有线程(可能很多)

您的代码禁止同一服务器访问中同一进程内的线程同时修改Cache对象。您可以跨进程甚至跨服务器创建锁,但随着您向上移动层次结构,成本会增加很多。

使用lock语句实际上并不锁定任何线程。但是,如果一个线程正在锁内执行代码(即在lock语句之后的代码块中),任何其他想要获取锁并执行相同代码的线程必须等到第一个线程持有锁离开代码块并释放锁。

C#lock语句使用轻量级锁定机制的Windows critical section。如果要锁定进程,可以使用mutex代替。要跨服务器锁定,您可以使用数据库或共享文件。

正如dkackman所指出的,.NET有一个AppDomain的概念,它是一种轻量级的进程。每个进程可以有多个AppDomain。 C#lock语句仅锁定单个AppDomain中的资源,并且层次结构的正确描述将包括进程下方和线程上方的AppDomain。但是,在一个过程中,您通常只有一个AppDomain,这使得区别变得无关紧要。

答案 1 :(得分:2)

C#lock语句锁定对象的特定实例(使用new object()创建的对象)。对象(在大多数情况下)不在AppDomains之间共享,因此如果您有10台服务器,则10个线程可以使用该段代码同时访问您的数据库。

答案 2 :(得分:2)

锁定不会阻塞线程。 它锁定了一个对象的实例。尝试访问它的每个线程都被阻止。 因此,在您的情况下,将尝试访问myLockHolder的每个线程都将被锁定,而不是所有线程。 换句话说,我们可以说Lock statement是使用Critical Section的语法糖。

就像你在MSDN中看到的那样:

  

lock(表达式)语句块

     

其中:

     

表达式 指定要锁定的对象。表达必须   是一个参考类型。通常情况下,   表达式将是这个,如果你   想要保护实例变量,   或者typeof(class),如果你愿意的话   保护一个静态变量(如果是   临界区发生在静态   给定类中的方法。)

     

语句块 关键部分的陈述。

答案 3 :(得分:1)

lock将阻止该应用程序中的所有线程访问myLockHolder对象。

因此,如果您运行了10个应用程序实例,那么当对象被锁定时,将向服务器发出10个请求。退出lock语句的那一刻,下一个请求将在该应用程序中处理,但只要Cache[key]不是null,它就不会访问数据库..

您获得的实际请求数量取决于此处发生的情况:

  if (Cache[key] == null)
  {
     Cache[key] = LengthyDatabaseCall();
  }

如果LengthyDatabaseCall();失败,下一个请求将尝试访问数据库服务器并检索信息,所以最好的情况是,只有10个请求到服务器。

答案 4 :(得分:0)

只有在另一个线程正在使用共享变量时需要访问共享变量的线程才会进入等待状态。

任何给定时间的数量很难确定。

答案 5 :(得分:0)

您的数据库将获得10个请求,可能性很高,请求2-10的运行速度比请求1快得多。