另一个锁定问题

时间:2008-09-30 21:38:13

标签: c# multithreading locking

我正试图让我的多线程理解被锁定。我正尽力自学,但其中一些问题需要澄清。

我用一段代码经历了三次迭代,尝试锁定。

在这段代码中,唯一需要锁定的是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语句? E.g。

bool isDumb;

lock (this.locker) isDumb = this.FieldAccessibleByMultipleThreads;

if (isDumb) ...

Vs以上。

lock (this.locker)
{
    if (this.FieldAccessibleByMultipleThreads) ...
}

3 个答案:

答案 0 :(得分:3)

1)在您启动另一个线程之前,您根本不必担心共享访问权限。

2)是的,您应该锁定对共享可变数据的所有访问权限。 (如果它是不可变的,则不需要锁定。)

3)不要使用GetHashCode()来指示线程ID。使用Thread.ManagedThreadId。我知道,有些书推荐使用Thread.GetHashCode() - 但请查看文档。

答案 1 :(得分:3)

  

关注锁定声明的范围?例如,如果我   需要在if语句中使用一个字段,并且该字段需要被锁定,   我应该避免锁定整个if语句吗?

一般来说,它应该是需要保护资源的代码部分的范围,而不是更多。这样就可以让其他线程尽快使用它。

但是取决于您锁定的资源是否是必须保持一致性的更大图片的一部分,或者它是否是与任何其他无直接关系的独立资源。

如果您有需要以同步方式进行所有更改的相互关联的部分,则需要在整个过程的持续时间内锁定整组部件。 如果您有一个独立的单个项目与其他任何东西分开,那么只需要锁定一个项目足够长的时间以便进程的一部分访问它。

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

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

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


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

答案 2 :(得分:0)

在开始任何线程之前无需锁定任何内容。

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