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

时间:2021-09-12 20:40:56

Maybe the question sounds silly, but I don't understand 'something about threads and locking and I would like to get a confirmation (here's why I ask).

也许问题听起来很愚蠢,但我不明白'关于线程和锁定的东西,我想得到一个确认(这就是我问的原因)。

So, if I have 10 servers and 10 request in the same time come to each server, that's 100 request across the farm. Without locking, thats 100 request to the database.

所以,如果我有10个服务器,同时有10个请求来到每个服务器,那就是整个服务器场的100个请求。没有锁定,那就是100请求数据库。

If I do something like this:

如果我做这样的事情:

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

How many database requests will I do? 10? 100? Or as much as I have threads?

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

6 个解决方案

#1


10  

You have a hierarchy of objects:

您有一个对象层次结构:

  • You have servers (10)
  • 你有服务器(10)
  • On each server you have processes (probably only 1 - your service/app pool)
  • 在每台服务器上,您都有进程(可能只有1个 - 您的服务/应用程序池)
  • In each process you have threads (probably many)
  • 在每个进程中你都有线程(可能很多)

Your code will only prohibit threads within the same process on the same server access to modify the Cache object simultaneously. You can create locks across processes and even across servers, but the cost increases a lot as you move up the hierarchy.

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

Using the lock statement does not actually lock any threads. However, if one thread is executing code inside the lock (that is in the block of code following the lock statement) any other thread that wants to take the lock and execute the same code has to wait until the first thread holding the lock leaves the block of code and releases the lock.

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

The C# lock statement uses a Windows critical section which a lightweight locking mechanism. If you want to lock across processes you can use a mutex instead. To lock across servers you can use a database or a shared file.

C#lock语句使用Windows关键部分,它是一种轻量级锁定机制。如果要锁定进程,可以使用互斥锁。要锁定服务器,您可以使用数据库或共享文件。

As dkackman has pointed out .NET has the concept of an AppDomain that is a kind of lightweight process. You can have multiple AppDomains per process. The C# lock statement only locks a resource within a single AppDomain, and a proper description of the hierarchy would include the AppDomain below the process and above the threads. However, quite often you only have a single AppDomain in a process making the distinction somewhat irrelevant.

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

#2


2  

The C# lock statement locks on a particular instance of an object (the object you created with new object()). Objects are (in most cases) not shared across AppDomains, thus if you are having 10 servers, 10 threads can run concurrently access your database with that piece of code.

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

#3


2  

Lock is not blocking threads. It is locking some instance of an object. And each thread which tries to access it is blocked. So in your case each thread which will try to access myLockHolder will be locked and not all the threads. In other words we can say that Lock statement is syntactic sugar for using Critical Section.

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

Like you can see in MSDN :

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

lock(expression) statement block

lock(表达式)语句块

where:

哪里:

expression Specifies the object that you want to lock on. expression must be a reference type. Typically, expression will either be this, if you want to protect an instance variable, or typeof(class), if you want to protect a static variable (or if the critical section occurs in a static method in the given class).

expression指定要锁定的对象。表达式必须是引用类型。通常,如果要保护实例变量,则表达式将为此;如果要保护静态变量(或者如果临界区出现在给定类中的静态方法中),则表达式将为typeof(类)。

statement block The statements of the critical section.

statement block关键部分的陈述。

#4


1  

lock will block all threads in that application from accessing the myLockHolder object.

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

So if you have 10 instances of the application running you'll get 10 requests to the server while the object is locked on each. The moment you exit the lock statement, the next request will process in that application, but as long as Cache[key] is not null, it won't access the database..

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

The number of actual requests you get depends on what happens here:

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

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

If LengthyDatabaseCall(); fails, the next request will try and access the database server and retrieve the information as well, so really your best case scenario is that there will only be 10 requests to the server.

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

#5


0  

Only the threads that need access to your shared variable at the moment another thread is using it will go into a wait state.

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

how many that is at any give time is hard to determine.

在任何给定时间有多少是很难确定的。

#6


0  

Your DB will get 10 requests, with odds being good that requests 2-10 run much faster than request 1.

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

#1


10  

You have a hierarchy of objects:

您有一个对象层次结构:

  • You have servers (10)
  • 你有服务器(10)
  • On each server you have processes (probably only 1 - your service/app pool)
  • 在每台服务器上,您都有进程(可能只有1个 - 您的服务/应用程序池)
  • In each process you have threads (probably many)
  • 在每个进程中你都有线程(可能很多)

Your code will only prohibit threads within the same process on the same server access to modify the Cache object simultaneously. You can create locks across processes and even across servers, but the cost increases a lot as you move up the hierarchy.

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

Using the lock statement does not actually lock any threads. However, if one thread is executing code inside the lock (that is in the block of code following the lock statement) any other thread that wants to take the lock and execute the same code has to wait until the first thread holding the lock leaves the block of code and releases the lock.

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

The C# lock statement uses a Windows critical section which a lightweight locking mechanism. If you want to lock across processes you can use a mutex instead. To lock across servers you can use a database or a shared file.

C#lock语句使用Windows关键部分,它是一种轻量级锁定机制。如果要锁定进程,可以使用互斥锁。要锁定服务器,您可以使用数据库或共享文件。

As dkackman has pointed out .NET has the concept of an AppDomain that is a kind of lightweight process. You can have multiple AppDomains per process. The C# lock statement only locks a resource within a single AppDomain, and a proper description of the hierarchy would include the AppDomain below the process and above the threads. However, quite often you only have a single AppDomain in a process making the distinction somewhat irrelevant.

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

#2


2  

The C# lock statement locks on a particular instance of an object (the object you created with new object()). Objects are (in most cases) not shared across AppDomains, thus if you are having 10 servers, 10 threads can run concurrently access your database with that piece of code.

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

#3


2  

Lock is not blocking threads. It is locking some instance of an object. And each thread which tries to access it is blocked. So in your case each thread which will try to access myLockHolder will be locked and not all the threads. In other words we can say that Lock statement is syntactic sugar for using Critical Section.

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

Like you can see in MSDN :

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

lock(expression) statement block

lock(表达式)语句块

where:

哪里:

expression Specifies the object that you want to lock on. expression must be a reference type. Typically, expression will either be this, if you want to protect an instance variable, or typeof(class), if you want to protect a static variable (or if the critical section occurs in a static method in the given class).

expression指定要锁定的对象。表达式必须是引用类型。通常,如果要保护实例变量,则表达式将为此;如果要保护静态变量(或者如果临界区出现在给定类中的静态方法中),则表达式将为typeof(类)。

statement block The statements of the critical section.

statement block关键部分的陈述。

#4


1  

lock will block all threads in that application from accessing the myLockHolder object.

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

So if you have 10 instances of the application running you'll get 10 requests to the server while the object is locked on each. The moment you exit the lock statement, the next request will process in that application, but as long as Cache[key] is not null, it won't access the database..

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

The number of actual requests you get depends on what happens here:

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

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

If LengthyDatabaseCall(); fails, the next request will try and access the database server and retrieve the information as well, so really your best case scenario is that there will only be 10 requests to the server.

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

#5


0  

Only the threads that need access to your shared variable at the moment another thread is using it will go into a wait state.

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

how many that is at any give time is hard to determine.

在任何给定时间有多少是很难确定的。

#6


0  

Your DB will get 10 requests, with odds being good that requests 2-10 run much faster than request 1.

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