Thread.Sleep(0)不能像描述的那样工作?

时间:2013-06-28 13:11:31

标签: c# thread-sleep

我目前正在阅读有关线程的this excellent article并阅读以下文字:

  

Thread.Sleep(0)立即放弃线程的当前时间片,自愿将CPU交给其他线程。

我想测试一下,下面是我的测试代码:

static string s = "";

static void Main(string[] args)
{
    //Create two threads that append string s
    Thread threadPoints = new Thread(SetPoints);
    Thread threadNewLines = new Thread(SetNewLines);

    //Start threads
    threadPoints.Start();
    threadNewLines.Start();

    //Wait one second for threads to manipulate string s
    Thread.Sleep(1000);

    //Threads have an infinite loop so we have to close them forcefully. 
    threadPoints.Abort();
    threadNewLines.Abort();

    //Print string s and wait for user-input
    Console.WriteLine(s);
    Console.ReadKey();
}

threadPoints和threadNewLines运行的函数:

static void SetPoints()
{
    while(true)
    {
        s += ".";
    }
}

static void SetNewLines()
{
    while(true)
    {
        s += "\n";
        Thread.Sleep(0);
    }
}

如果我正确理解Thread.Sleep(0),输出应该是这样的:

............        |
..............      |
................    | <- End of console
..........          |
.............       |
...............     |

但我得到这个作为输出:

....................|
....................|
....                |
                    |
                    |
....................|
....................|
.................   |
                    |

看到文章开头提到的文章是很多程序员强烈推荐的,我只能假设我对Thread.Sleep(0)的理解是错误的。所以,如果有人能够澄清,我会非常感激。

5 个答案:

答案 0 :(得分:2)

什么thread.sleep(0)是释放cpu来处理其他线程,但这并不意味着另一个线程不能是当前线程。如果您尝试将上下文发送到另一个线程,请尝试使用某种信号。

答案 1 :(得分:1)

如果您可以访问仅具有单个核心/处理器的计算机(或可能是VM),请尝试在该计算机上运行您的代码。您可能会对结果的变化感到惊讶。仅仅因为两个线程引用相同的变量“s”,并不意味着它们实际上同时引用相同的值,因为现代多核(甚至只是并行管道)CPU可能发生各种级别的缓存。如果您想了解如何在不考虑缓存问题的情况下如何工作,请尝试将每个s +=表达式包装在lock语句中。

答案 2 :(得分:1)

如果您将控制台的宽度扩展为比当前大5倍,那么您将看到您所期望的,线条未达到控制台宽度。问题是一个时间片实际上很长。因此,要使用普通控制台获得预期效果,您必须减慢Points线程,但不使用Sleep。而不是while (true)循环尝试此

for (int i = 0;; i++)
{
  if (int % 10 == 0)
    s += ".";
}

要减慢线程速度,请使用更大的数字替换数字10。

答案 3 :(得分:0)

处理器处理的下一个线程是随机线程,它甚至可能是您刚刚调用Thread.Sleep(0)的相同线程。为了确保下一个线程不是同一个线程,你可以调用Thread.Yield()并检查它的返回结果 - 如果os有另一个可以运行true的线程将被返回,否则为false。

答案 4 :(得分:-1)

你应该(几乎)永不中止线程。最好的做法是表示他们死亡(自杀)。

这通常是通过设置一些布尔变量来完成的,并且线程应检查其值是否继续执行。

您正在设置名为“s”的字符串变量。你会在比赛条件下招致。字符串不是线程安全的。您可以将操作它的操作包装在一个锁中,或者使用一个线程安全的内置类型。

请始终注意,在文档中,要知道您使用的类型是否是线程安全的。

因此,您无法依赖结果,因为您的程序不是线程安全的。 如果您多次运行该程序,我的猜测是您将获得不同的输出。

注意:使用布尔值共享某些状态以取消线程时,请确保将其标记为 volatile JIT可能会优化代码,并且永远不会查看其更改后的值。