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

我目前正在阅读这篇关于线程的优秀文章 ,并阅读以下文字:

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

但我得到这个作为输出:

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

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

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

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

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

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

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

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

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

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

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

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

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

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