c# - 当我使用线程将内容打印到控制台时,为什么会产生奇怪的结果?

标签 c# multithreading thread-safety

我最近在阅读 Rob Miles (here) 的非常好的 pdf 时开始接触 Threads。他在第 160 页(2012,C# pdf)上有一个例子,但它没有写入控制台,只是做了空循环。

我写了一个非常简单的线程生成循环,它创建了 10 个线程,这些线程在每 1000 的倍数上将它们的 ID 写入屏幕。这很好 - 它向我展示了线程是如何一起运行的。我的问题以为什么我的输出如此困惑开始?通常,当我运行下面的程序时,我会看到多行“Thread 3 Finished”,我很确定,我应该每行只有一个。

我添加了一个 "lock"从 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();
}

详情请看这里:

Access to Modified Closure

Eric Lippert's Article on Closures

关于c# - 当我使用线程将内容打印到控制台时,为什么会产生奇怪的结果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16519963/

相关文章:

c# - 拆分器控件(winforms)

c# 数据从数据网格到文本框?

c# - 使用浏览器后退按钮加载 ASP.NET 页面

c# - 如何修复捕获TimeoutException?

java - 在 Java 中,是否需要将简单赋值同步到静态?

c# - 这个线程安全吗?

c# - 如何根据asp.net母版页中的用户权限从菜单中删除项目

multithreading - 在Delphi中,System.TMonitor.Pulse和TMonitor.PulseAll实际上做了什么

java - 线程和同步一般方法

c++ - 队列内存泄漏