另一个锁定问题
我试图将我对多线程的理解锁定下来。我正在尽力自学,但是其中一些问题需要澄清。
我用一段代码经历了三个迭代,尝试了锁定。
在此代码中,唯一需要锁定的是this.managerThreadPriority。
首先,简单的过程方法具有最小限度的锁定。
var managerThread = new Thread ( new ThreadStart(this.ManagerThreadEntryPoint) ); lock (this.locker) { managerThread.Priority = this.managerThreadPriority; } managerThread.Name = string.Format("Manager Thread ({0})", managerThread.GetHashCode()); managerThread.Start();
接下来,使用一条语句来创建和启动新线程,但是锁的作用域似乎太大,无法包括线程的创建和启动。在使用this.managerThreadPriority之后,编译器无法以某种方式神奇地知道可以释放该锁。
我想应该避免这种天真的锁定。
lock (this.locker) { new Thread ( new ThreadStart(this.ManagerThreadEntryPoint) ) { Priority = this.managerThreadPriority, Name = string.Format("Manager Thread ({0})", GetHashCode()) } .Start(); }
最后,创建和启动新线程的一条语句,仅在共享字段周围具有"嵌入式"锁。
new Thread ( new ThreadStart(this.ManagerThreadEntryPoint) ) { Priority = new Func<ThreadPriorty>(() => { lock (this.locker) { return this.managerThreadPriority; } })(), Name = string.Format("Manager Thread ({0})", GetHashCode()) } .Start();
关心评论锁语句的作用域吗?例如,如果我需要在if
语句中使用一个字段并且该字段需要被锁定,是否应该避免锁定整个if
语句?例如。
bool isDumb; lock (this.locker) isDumb = this.FieldAccessibleByMultipleThreads; if (isDumb) ...
VS.
lock (this.locker) { if (this.FieldAccessibleByMultipleThreads) ... }
解决方案
1)甚至无需启动另一个线程,就不必担心完全共享对其的访问。
2)是,我们应该锁定对共享可变数据的所有访问。 (如果它是不可变的,则不需要锁定。)
3)不要使用GetHashCode()来指示线程ID。使用Thread.ManagedThreadId。我知道,有些书推荐Thread.GetHashCode(),但请看一下文档。
在启动任何线程之前,无需锁定任何内容。
如果我们只打算读取变量,那么也不需要锁。在混合读写时,我们需要使用互斥锁和类似的锁定,并且我们需要同时锁定读取和写入线程。
Care to comment about the scoping of lock statements? For example, if I need to use a field in an if statement and that field needs to be locked, should I avoid locking the entire if statement?
通常,应将其范围限定在需要保护资源的那部分代码中,而不能超过此范围。这样一来,其他线程便可以尽快使用它。
但是,这取决于我们锁定的资源是否是必须保持一致性的更大视图的一部分,还是它是与其他任何资源都不直接相关的独立资源。
如果我们有相互关联的部分,需要以同步的方式进行所有更改,则需要在整个过程中锁定整个部分。
如果我们有一个独立的单个项目与其他任何项目脱钩,则只需锁定一个项目足够长的时间,以便过程的一部分可以访问它。
换句话说,我们是在保护对资源的同步访问还是异步访问?
通常,同步访问需要将其保留更长的时间,因为它关心的是资源所属的更广阔的前景。它必须与相关资源保持一致。在这种情况下,如果要防止在处理完所有内容之前就进行中断,则可以很好地包装整个for循环。
异步访问应尽可能短地保持不变。因此,更合适的位置是在代码内部,例如在for循环或者if语句内部,这样我们就可以立即释放单个元素,甚至在处理其他元素之前也可以。
除了这两个考虑因素之外,我还要再添加一个。避免嵌套涉及两个不同锁定对象的锁。我从经验中了解到,这可能是死锁的来源,尤其是在代码的其他部分使用死锁的情况下。如果这两个对象一直是一个组的一部分,需要始终将其视为一个整体,则应重构此类嵌套。