关于C#中的lock语句的困惑

这来自MSDN:lock关键字确保一个线程不进入代码的关键部分 ,而另一个线程在关键部分

关键部分是否必须与关键部分相同?

或者它是否意味着:lock关键字确保一个线程不会进入代码对象保护的任何关键部分 ,而另一个线程处于由同一对象保护的任何关键部分 。 ?

class Program { static void Main(string[] args) { TestDifferentCriticalSections(); Console.ReadLine(); } private static void TestDifferentCriticalSections() { Test lo = new Test(); Thread t1 = new Thread(() => { lo.MethodA(); }); t1.Start(); Thread t2 = new Thread(() => { lo.MethodB(); }); t2.Start(); } } public class Test { private object obj = new object(); public Test() { } public void MethodA() { lock (obj) { for (int i = 0; i < 5; i++) { Thread.Sleep(500); Console.WriteLine("A"); } } } public void MethodB() { lock (obj) { for (int i = 0; i < 5; i++) { Thread.Sleep(500); Console.WriteLine("B"); } } } } 

问题是令人困惑的措辞,到目前为止的答案也不是特别清楚。 让我把这个问题改成几个问题:

(1)lock语句是否确保在任何时候锁定语句的主体中都不超过一个线程?

。 例如:

 static readonly object lock1 = new object(); static readonly object lock2 = new object(); static int counter = 0; static object M() { int c = Interlocked.Increment(ref counter); return c % 2 == 0 ? lock1 : lock2; } ... lock(M()) { Critical(); } 

两个线程可能同时位于lock语句的主体中,因为lock语句锁定了两个不同的对象。 线程Alpha可以调用M()并获取lock1,然后线程Beta可以调用M()并获取lock2。

(2)假设我的lock语句总是锁定在同一个对象上,lock语句是否确保一次锁定主体中只有一个“活动”线程?

是。 如果你有:

 static readonly object lock1 = new object(); ... lock(lock1) { Critical(); } 

然后线程Alpha可以获取锁定,线程Beta将阻塞,直到锁定可用,然后才能进入锁体。

(3)假设我有两个锁定语句,并且每次锁定语句都锁定在同一个对象上,锁定语句是否确保一次锁定的主体中只有一个“活动”线程?

是。 如果你有:

 static readonly object lock1 = new object(); ... static void X() { lock(lock1) { CriticalX(); } } static void Y() { lock(lock1) { CriticalY(); } } 

然后,如果线程Alpha在X中并且获取锁定,并且线程Beta在Y中,则线程Beta将阻塞,直到锁定可用,然后才能进入锁体。

(4)你为什么把“活跃”放在“恐慌报价”中?

要注意等待线程可能在锁体中的事实。 您可以使用Monitor.Wait方法“暂停”锁定主体中的线程,并允许阻塞的线程变为活动状态并进入该锁定主体(或锁定同一对象的其他锁定主体)。 等待线程将保持其“等待”状态,直到脉冲。 在脉冲之后的某个时间,它重新加入“就绪”队列并阻塞,直到锁中没有“活动”线程。 然后它从它停止的位置恢复。

你锁定了一个物体。 如果另一个线程试图同时访问该对象标记的关键部分,它将阻塞,直到锁被删除/完成。

例:

 public static object DatabaseLck= new object(); lock (DatabaseLck) { results = db.Query(query).ToList(); } 

要么

 lock (DatabaseLck) { results = db.Query(string.Format(query, args)).ToList(); } 

这些代码块中的任何一个都不能同时运行,因为它们使用相同的锁对象。 如果您为每个锁定对象使用了不同的锁定对象,则它们可以同时运行。

它是同一个关键部分。

 lock (synclock) { // the critical section protected by the lock statement // Only one thread can access this at any one time } 

请参阅MSDN上的lock语句 :

lock关键字通过获取给定对象的互斥锁,执行语句,然后释放锁来将语句块标记为关键部分。


或者它的意思是:lock关键字确保一个线程不会进入任何关键的代码段,而另一个线程处于任何关键部分。 ?

。 这并不意味着。 它意味着由该锁保护的关键部分和单独的锁。


更新,代码示例如下:

如果使用单个对象锁定,它将锁定所有关键部分,导致其他线程阻塞直到释放。 在您的代码示例中,一旦输入了MethodA的锁,到达该锁的所有其他线程和MethodB上的锁将被阻塞,直到锁被释放(这是因为您在两个方法中锁定了同一个对象)。

它并不意味着任何 ,尽管你可以通过用同一个对象锁定它们来保护2个代码块同时被多个线程输入。 这是一种常见的范例 – 您可能希望锁定集合以进行清除和写入。

不,这意味着另一个线程不会进入受此锁定语句保护的临界区。

Critical部分仅由程序员定义,在这种情况下,您可以将其替换为:受锁保护的部分

所以翻译: lock关键字确保一个线程不会输入受lock保护的代码段,而另一个线程位于此段代码中(受lock保护)

它所讨论的关键部分是由锁定语句保护的部分。

锁定在同一对象上的任何关键部分都将被阻止访问。

锁对象也是静态的也很重要,因为锁需要锁定(或试图锁定)锁对象的同一个实例。