究竟什么“锁定”锁定?

我正在创建一个创建和管理多个套接字连接的类,它将从套接字接收的信息转发到主线程,反之亦然。 我传递大量信息的multithreading对我来说是新的(就像C#中的大多数事情一样),所以我需要澄清locks究竟是做什么的。

当我锁定方法的一部分时,它只确保没有其他线程可以进入该部分代码,或者它是否确实阻止该部分代码中的所有变量被其他线程修改,无论它们出现在何处?

例如:

 public class TestLock { public volatile int a = 0; public volatile int b = 2; private object ALock = new Object(); public TestLock() { } public void UnlockEdit(int atemp, int btemp) { a = atemp; b = btemp; } public void LockedEdit(int atemp, int btemp) { lock(ALock) { a = atemp; b = btemp; } } public int[] ReturnValues() { int[] ret = new int[2]; lock (ALock) { ret[0] = a; ret[1] = b; } return ret; } } 

如果线程A调用LockedEdit方法并在线程B进入UnlockEdit之前稍微到达锁定。 怎么了? 锁会阻止线程B修改ab吗? 它会阻止吗? 或者锁只适用于一个特定的代码分支? 或者我应该将相同的lock对象( ALock )应用于我想要修改和从多个线程读取的对象的每个读取和写入方法?

lock语句在代码中创建一个关键部分 。 这可以防止其他线程进入锁定语句括号内的代码。 其他线程基本上等到轮到他们进入该部分。

它不会阻止其他线程修改类中的变量。 例如,TestLock.a和TestLock.b可以通过TestLock类中不使用Lock(ALock)语句的函数进行修改。 此外,由于变量a和b是公共的,因此可以通过类外部的代码(在单独的线程上)进行修改。

这是.NET Basic Threading的一个很好的链接:

来自MSDN:

lock关键字确保一个线程不进入代码的关键部分,而另一个线程处于临界区。 如果另一个线程试图输入锁定的代码,它将等待,阻止,直到该对象被释放。

下面是一些代码的示例,它为multithreading应用程序保持变量安全(取自C#3.0 cookbook ):

  public static class SaferMemberAccess { private static int numericField = 1; private static object syncObj = new object( ); public static void IncrementNumericField( ) { lock(syncObj) { ++numericField; } } public static void ModifyNumericField(int newValue) { lock(syncObj) { numericField = newValue; } } public static int ReadNumericField( ) { lock (syncObj) { return (numericField); } } } 

当我锁定方法的一部分时,它只确保没有其他线程可以进入该部分代码,或者它是否确实阻止该部分代码中的所有变量被其他线程修改,无论它们出现在何处?

这个问题是如此复杂和不完整,以至于无法回答。 我们重写一下吧。

当我锁定方法的一部分时,它确保没有其他线程可以进入该部分代码吗?

是。 然而,更准确的说明方式是:在获得与给定给lock语句的“monitor”对象相关联的锁之前,不能输入锁定的部分。 该锁定一次只能由一个线程获得。

我还注意到,在涉及监视器的更高级用法的场景中如何获得锁定存在微妙之处,例如脉冲。 再次,请仔细阅读文档,以获取有关监视器操作的确切语义的说明。

当我锁定方法的一部分时, 它只确保没有其他线程可以进入该部分代码吗?

不能。采取锁定还有其他行动,而不仅仅是确保阻止相互排斥。 例如,它引入了一个内存屏障。

它是否实际上阻止了该部分代码中的所有变量被其他线程修改,无论它们出现在何处?

当然不是!

锁会阻止线程B修改a和b吗?

你建造了一个带门的浴室,一侧有锁,一侧对外开放。 你锁上卫生间的门。 这似乎是一种有效的方法,确保每次只能挤出一个牙膏吗?

它会阻止吗?

会阻止什么?

锁只适用于一个特定的代码分支吗?

我无法理解这个问题。

我应该将相同的“锁定”对象(ALock)应用于我想要修改和从多个线程读取的对象的每个读取和写入方法吗?

是。

你没有提出的问题,但应该有:

我应该首先使用共享内存multithreading吗?

可能不是。 即使是专家也很难做到这一点。 如果我正在进行套接字编程,我首先使用async-await或任务并行库来管理我的异步,而不是直接参与线程。 线程是专门针对专家的低级工具; 尝试提高几个级别的抽象级别。

你像在这里一样获得对象的锁定

 lock(ALock) 

代码的这一部分现在被此对象锁定,并且在释放锁之前没有其他对象可以进入,即此对象离开临界区。

这也意味着在这个时候没有其他对象能够修改临界区中此对象锁定的变量。