C# 为什么这个线程会导致我的应用程序在多次执行后挂起?

C# 为什么这个线程会导致我的应用程序在多次执行后挂起?,c#,multithreading,C#,Multithreading,我创建此测试程序是为了更好地理解线程: namespace ThreadTest { public class Class1 { static Number number = new Number(); static public void Go() { Thread t1 = new Thread(new ThreadStart(IncrementNumber)); t1.Star

我创建此测试程序是为了更好地理解线程:

namespace ThreadTest
{
    public class Class1
    {
        static Number number = new Number();

        static public void Go()
        {
            Thread t1 = new Thread(new ThreadStart(IncrementNumber));
            t1.Start();
            IncrementNumber();
        }

        public static void IncrementNumber()
        {
            number.Inc();
        }
    }

    public class Number
    {
        int x = 0;

        public void Inc()
        {

                x++;
                Debug.Write(x);
                Debug.Write(Environment.NewLine);
        }

        public override string ToString()
        {
            return x.ToString();
        }
    }
}
我只是通过调用ThreadTest.Class1.Go()从即时窗口执行它。我注意到,从一次执行到下一次执行,只要不需要重新编译,静态成员就会保留在内存中,并继续重用它们

以下是连续执行四次后立即窗口的外观:

ThreadTest.Class1.Go()
2
1
Expression has been evaluated and has no value
ThreadTest.Class1.Go()
3
4Expression has been evaluated and has no value
ThreadTest.Class1.Go()
ThreadTest.Class1.Go()
An expression evaluation is already in progress.
第一次执行看起来和我预期的一样

第二次执行未能写入最终的Environment.NewLine。这是否可能是因为主线程的执行在t1上执行之前就完成了,所以t1有时间写入数字,而不是新行?这似乎不太可能,但这是我现在能想到的唯一解释


第三次执行只是挂起,第四次尝试执行它的输出证明了这一点。为什么它会挂起?

事实上,主线程的执行可能会在此时停止

如果您在不同的运行中获得不同的输出,则可以很好地说明这种情况正在发生

您需要更好地描述“挂起”以完全回答这方面的问题。如果根本没有输出,则表明主线程在
t1
的任何输出之前完成。如果没有输出,但程序没有结束,请尝试中断执行并查看每个线程在哪一行寻找线索


尝试在主线程中加入
t1
,以防止程序在准备退出之前退出。

实际上,您的“应用程序”有一点随机行为。您创建了一个只执行一次的线程(那么线程的意义是什么呢?),但您不处理它。您将值存储在静态变量中(它们之间没有任何同步,x甚至不易失性),然后在即时窗口中执行它…使用所有这些东西…它为什么挂起真的很重要吗?@Adriano所有优点。我知道我可以用课本上的例子来说明做这件事的正确方法,但我正在努力理解到底发生了什么。我不知道它怎么可能挂起,因为这个程序中绝对没有任何东西应该等待或阻止任何东西。我可以预见未来的问题,在一个多次调用特定例程的大型程序上可能会发生类似的情况。我宁愿用一个小例子来说明这一点,这样我就可以了解发生了什么,以防在更重要的事情上遇到它。我同意,但你应该尝试使用一个简单的控制台应用程序。在这里您添加了更多未知变量(即时窗口中发生了什么?。@Adriano True。。。我会试试看。加入t1会像我想象的那样修复它,但这仍然让我想知道为什么它挂起时没有那条线(有些情况下你不想加入,所以我仍然想弄清楚)。从一次试验到下一次试验,输出(与原始代码)的唯一差异是,有时4也不会打印出来。我认为这支持了主线程在t1之前结束的概念。我相信它在下一次执行时挂起的原因与t1在上一次运行时没有完成这一事实有关。我认为它应该每次实例化一个新线程并丢弃旧线程(即使它仍然存在)尽管如此,我不完全理解为什么这会使它挂起。一旦主线程结束,进程就会退出。在那一点上,所有t1的痕迹都应该被消除。。。似乎只有在t1完成之前主线程退出之后,它才会挂起。我认为Adriano有一个很好的观点,就是把它作为一个控制台应用程序来运行,而不是使用即时窗口。。。我试过了,它再也挂不住了。(为了清楚起见,我把它变成了一个控制台应用程序,在Main方法中,我连续调用了25次Go(),通过从即时窗口调用它来模拟我正在做的事情)。