While 循环计时在多线程 C# 中如何工作?

How does While Loop timing work in C# w/ multiple threads?

我有一个可以从多个线程更新的 isRunning 布尔变量。只要 isRunning 为真,我就有一个 while 循环。在循环开始时,它会立即再次检查布尔值是否为真。从概念上讲,我可以看到 while 循环将 isRunning 视为 true 的情况,然后另一个线程在处理 if 语句之前更新该值。在实践中,我想象 isRunning 的时间跨度会有亚毫秒的变化,以便永远命中 if 语句。对我来说,这感觉就像臭代码。

while(isRunning) {
       //isRunning gets updated by another thread??
   if(!isRunning) {
      //Will this ever get hit???
   }
 }

if 块是否会被触发?在执行 while 检查和紧接着执行 if 检查之间有什么样的时间跨度?我将如何进行试验?

可以提出各种理论论据,但让我们试一试。我不会很小心,因为那不是重点。重点是区分击中 if 方块是否是天文学上罕见的事件。

例如:

static void Main()
{
    int IfBlockHitCount = 0;
    for (int i = 0; i < 1000; i++)
    {
        Thread runner = new Thread(RandomlyResetRunningFlag);
        IsRunning = true;
        runner.Start();
        while (IsRunning)
        {
            if (!IsRunning)
                IfBlockHitCount++;
        }
    }

    Console.WriteLine(IfBlockHitCount);
}

static volatile bool IsRunning;
static volatile int sink;

static void RandomlyResetRunningFlag()
{
    Random r = new Random();
    int spinCount = r.Next(1000, 1000000);
    for (int i = 0; i < spinCount; i++)
        sink = 0;
    IsRunning = false;
}

我 运行 这几次,打印出相当多的数字,通常不到 500(即不到一半的时间)。由此我得出结论,是的,击中那个 if 块是可能的

但是为什么呢?我提出这个解释。由于正在执行忙等待的线程基本上在做两件事:

  1. while 的条件下检查 IsRunning
  2. if 的条件下检查 IsRunning

真的没有其他地方可以花时间。给定一个 运行dom-ish 时间,在该时间首次观察到 IsRunningfalse,在这两种情况中的任何一种情况下都有很大的机会。如果线程实际上 正在做 任何事情,那将大大改变结果。它改变它的方式取决于线程在何处做某事:

while (IsRunning)
{
    // A
    if (!IsRunning)
        IfBlockHitCount++;
    // B
}

如果在位置 A 中添加更多代码,那么它更有可能执行 if 块。如果在 B 位置添加更多代码,则执行 if 块的可能性会降低。

换句话说:这并不是 window 时间有多短的问题,而是相对于 [=57] 之外的时间量而言它有多大的问题=].如果没有其他事情发生,即使是很短的 window 也可以涵盖整个时间线的大部分内容。

顺便说一下,IsRunning 必须是 volatile,否则整个问题就没有意义了。 (作为对专家的提醒,C# volatile 与 C++ volatile 不同 并且实际上适用于这种用法,尽管不一定推荐) 我还制作了一个 volatile sink,以强制 运行dom-duration 等待循环实际执行某些操作,如果循环被优化掉,那就太糟糕了。