[英]When I use threads to print things to the console, why does it produce odd results?
我最近在閱讀Rob Miles( 這里 )的非常好的pdf時進入了Threads。 他在第160頁(2012,C#pdf)上有一個例子,但它沒有寫入控制台只是空循環。
我寫了一個非常簡單的線程生成循環,它創建了10個線程,在1000的每個倍數上將它們的ID寫入屏幕。這很好 - 它向我展示了線程如何一起運行。 我的問題從為什么我的輸出如此困惑開始? 通常當我運行下面的程序時,我會得到多個“Thread 3 Finished”行,我很確定,我應該只有一個。
我從MSDN添加了一個“鎖定”到循環但它似乎仍然產生奇數輸出(我將在下面舉一個例子)。
namespace ConsoleApplication1
{
class Program
{
static object sync = new object();
static void Main(string[] args)
{
for (int i = 0; i < 10; i++)
{
Thread myThread = new Thread(() => DoThis(i));
myThread.Start();
}
Console.ReadLine();
}
static void DoThis(int s)
{
lock (sync) // a new addition that hasn't helped
{
for (long j = 0; j < 10000; j++)
{
if (j % 1000 == 0) Console.Write(String.Format("{0}.", s));
}
Console.WriteLine("\r\nThread {0} Finished", s);
Debug.Print("\r\nThread {0} Finished", s); //<-- added to debug
}
}
}
}
我以為我做得很好 - 我有局部變量(我的計數循環),我有一個int傳遞大概不是通過引用,后來我試圖鎖定它做它的循環。 沒有快樂。我需要做些什么來使輸出看起來合理? 我試過Deubg.Print進行故障排除,但它也有錯誤(下面)。
最終,我想在更大的應用程序中使用線程,但如果我不能在這里得到它,我不確定我想要!
示例最后從debug.print行輸出:(注意倍數)...
Thread 1 Done The thread '<No Name>' (0x15cc) has exited with code 0 (0x0). Thread 9 Done The thread '<No Name>' (0x1d0c) has exited with code 0 (0x0). Thread 6 Done The thread '<No Name>' (0x2248) has exited with code 0 (0x0). Thread 10 Done The thread '<No Name>' (0x22bc) has exited with code 0 (0x0). Thread 9 Done The thread '<No Name>' (0x85c) has exited with code 0 (0x0). Thread 9 Done The thread '<No Name>' (0x1628) has exited with code 0 (0x0). Thread 3 Done The thread '<No Name>' (0x2384) has exited with code 0 (0x0). Thread 6 Done Thread 2 Done Thread 4 Done The thread '<No Name>' (0x2348) has exited with code 0 (0x0). The thread '<No Name>' (0x2420) has exited with code 0 (0x0). The thread '<No Name>' (0x1ea8) has exited with code 0 (0x0).
如果我可以提供有關我嘗試過的更多信息,請告訴我。
這里的問題是你在循環變量上使用了“修改后的閉包”。
雖然這已針對foreach
循環進行了修復,但for
循環仍有問題(並且總會如此)
要解決此問題,請將Main()更改為:
static void Main(string[] args)
{
for (int i = 0; i < 10; i++)
{
int copy = i; // Make a copy of i to prevent the "modified closure" problem.
Thread myThread = new Thread(() => DoThis(copy));
myThread.Start();
}
Console.ReadLine();
}
有關詳細信息,請參見此處
嘗試使用Parallel.For
而不是自己在循環中啟動線程:
Parallel.For(0, 10, DoThis);
如果你需要傳遞一個額外的參數(比如w
)作為其中的一部分,那么你可以這樣做:
var w = 4;
Parallel.For(0, 10, i => DoThis(i, w));
當然要考慮的另一件事是Console
對象是獨占的。 如果您從一個線程使用它,那么嘗試使用它的任何其他線程將被阻塞,直到它完成。
此外,您的lock (sync)
將阻止任何兩個線程同時執行其操作。
請記住,不保證您的線程以任何特定順序執行。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.