6

假设多个线程周期性地执行DoWork()下面的方法。假设在某个时刻,两个线程几乎同时开始执行此方法,因此两个本地时间戳对象中的一个比另一个大一个刻度。

ICollection collection = // ...

public void DoWork()
{
    DateTime timestamp = DateTime.Now;

    lock(collection.SyncRoot)
    {
        // critical section
    }
}

如果线程 A 的特征是时间戳等于t1,而线程 B 的特征是时间戳t2等于t1 + 1 tick,那么线程 A 将首先需要访问临界区。

.NET 如何管理多线程对临界区的访问?它是否将访问请求放入队列中,以便它们按时间顺序排列?也就是说,是否按照线程访问请求的顺序来保证对临界区的访问?

4

2 回答 2

6

绝对不能保证线程执行的顺序以及哪个线程首先获得临界区。

请注意,即使线程的优先级也不能保证顺序 - 不同的核心/CPU可以同时执行不同优先级的线程,任何线程都可以先到达并获得临界区。

注意 2:线程也可以在任意时刻被调度执行/等待,因此同一线程中的 2 个不同操作彼此相邻这一事实并不意味着它们将在其间没有延迟地一个接一个地执行。在您的情况下,这意味着线程 A 可能会在获得时间戳后立即停止,而计划在稍后执行的线程 B 将很容易获得稍后的时间戳,但首先到达临界区。

于 2012-09-05T17:24:37.107 回答
4

你做了一个很高的假设,一个永远让程序员在线程方面遇到麻烦的假设。首先获得时间戳的线程肯定不能保证也首先进入锁。只有几率很高,不是100%。线程被操作系统调度程序抢占。这可以中断任何线程,包括刚刚开始执行 Monitor.Enter() 方法调用的线程。然后调度决策很可能会暂停 A 并允许 B 先获得锁。

调度程序也不需要修改订单。执行 A 的核心可能在其数据缓存中没有“集合”对象引用,从而在等待内存总线以允许执行 B 的核心领先时使核心停止足够长的时间。“种族”这个词是合适的,在这里做出错误的假设会导致代码中出现线程竞争错误。

锁背后的机制由处理器实现,处理器是唯一可以确保没有“相同时间”的实体。每个多核 cpu 都实现了比较和交换原子指令。您可以在此答案中看到 .NET 使用的版本。

于 2012-09-05T18:17:45.977 回答