我目前正在阅读有关线程的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)的理解是错误的。所以,如果有人能够澄清,我会非常感激。
答案 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可能会优化代码,并且永远不会查看其更改后的值。