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) ...

比。

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

3 回答 3

3

想评论锁定语句的范围?例如,如果我需要在 if 语句中使用一个字段并且该字段需要被锁定,我是否应该避免锁定整个 if 语句?

一般来说,它的范围应该是需要保护资源的代码部分,仅此而已。这是为了让其他线程尽快使用它。

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

如果您有相互关联的部分需要以同步方式全部更改,则需要在整个过程中锁定整套部分。如果您有一个独立的单个项目与其他任何项目解耦,那么只需将一个项目锁定足够长的时间,以便部分流程可以访问它。

另一种说法是,您是在保护对资源的同步还是异步访问

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

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


除了这两个考虑之外,我还要补充一个。避免嵌套涉及两个不同锁定对象的锁。我从经验中了解到,这很可能是死锁的来源,尤其是在代码的其他部分使用它们的情况下。如果这两个对象是一个组的一部分,需要一直被视为一个整体,那么这种嵌套应该被重构出来。

于 2008-10-01T04:47:19.357 回答
3

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

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

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

于 2008-09-30T21:43:23.933 回答
0

在启动任何线程之前无需锁定任何内容。

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

于 2008-09-30T21:54:50.707 回答