2008-09-30 71 views
1

我试图让我的多线程理解锁定。我尽我所能教导自己,但其中一些问题需要澄清。另一个锁定问题

我已经通过一段代码尝试了三次迭代。

在这段代码,需要锁定的唯一事情是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) ... 
} 

回答

3

1)之前,你甚至开始另一个线程,你不必担心共享访问它。

2)是的,你应该锁定全部访问共享可变数据。 (如果这是不可改变的,因此不需要锁定。)

3)不要使用GetHashCode()方法来表示线程ID。使用Thread.ManagedThreadId。我知道,有推荐Thread.GetHashCode()的书 - 但看看文档。

0

在开始任何线程之前,没有必要锁定任何东西。

如果你只是要读取一个变量,那么也不需要锁。当你读写混合时,你需要使用互斥锁和类似的锁,并且你需要锁定读和写线程。

+0

即使您只在一个线程中读取并在另一个线程中写入,仍然需要锁定读取线程 - 否则不能保证您将看到来自其他线程的新写入的数据。 – 2008-09-30 22:00:56

3

护理约锁定报表的范围界定有何评论?例如,如果我 需要使用if语句中的字段并且该字段需要锁定,我应该避免锁定整个if语句吗?

一般来说,它的范围应该是需要资源被守护的代码部分,并且不能超过这个范围。这可以让其他线程尽快使用它。

它取决于你所锁定的资源是否具有保持一致性,抑或是没有直接关系的其他任何一个独立的资源更大的图片的一部分。

如果您有相互关联的零件需要全部以同步方式进行更改,那么整套零件需要在整个过程期间锁定。 如果你有一个独立的单一项目与其他任何东西没有耦合,那么只有一个项目需要被锁定足够长的时间,以便部分过程访问它。

另一种说法是是否保护对资源的同步或异步访问?

同步访问通常需要保持较长的时间,因为它关心资源所属的更大图片。它必须保持与相关资源的一致性。在这种情况下,如果你想防止中断,直到全部处理完毕,你可能会很好地包装整个for循环。

异步访问应尽可能简短地保留它。因此,更合适的锁定位置将放在代码的部分内部,例如for循环或if语句中,以便在处理其他代码之前立即释放单个元素。


除了这两个考虑因素之外,我还会再增加一个。 避免嵌套涉及两个不同锁定对象的锁。我从经验中了解到,它可能是死锁的来源,特别是如果代码的其他部分使用它们。如果这两个对象是需要一直视为一个整体的组的一部分,则应该重构此类嵌套。