簡體   English   中英

當我使用線程將東西打印到控制台時,為什么會產生奇怪的結果呢?

[英]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();
}

有關詳細信息,請參見此處

訪問Modified Closure

Eric Lippert關於閉包的文章

嘗試使用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM