【问题标题】:Why does this thread cause my application to hang up after multiple executions?为什么这个线程会导致我的应用程序在多次执行后挂起?
【发布时间】:2014-04-24 05:01:11
【问题描述】:

我创建了这个测试程序来尝试更好地理解线程:

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 有时间写入数字,而不是新行?这似乎不太可能,但这是我现在能想到的唯一解释。

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

【问题讨论】:

  • 实际上你的“应用程序”有一点随机行为。您创建了一个只执行一次的线程(那么线程的意义何在?)但您不处置它。您将值存储在静态变量中(它们之间没有任何同步,并且 x 甚至不是易失性的),然后在即时窗口中执行它......所有这些东西......它为什么挂起真的重要吗?
  • @Adriano 所有的优点。我知道我可以去获取一个教科书示例,说明执行此类操作的正确方法,但我试图了解真正发生了什么。我不知道它怎么可能挂起,因为这个程序中绝对没有任何东西应该等待任何东西或阻止任何东西。我可以预见一个未来的问题,这样的事情可能会发生在一个多次调用特定例程的大型程序上。我宁愿通过一个小例子来解决这个问题,以便我了解发生了什么,以防我遇到更重要的事情。
  • 我同意,但您应该尝试使用简单的控制台应用程序。在那里添加更多未知变量(即时窗口内发生了什么?)。
  • @Adriano True...我会试试的。

标签: c# multithreading


【解决方案1】:

确实,主线程的执行可能已经停止。

如果您在不同的运行中得到不同的输出,一个很好的迹象表明这种情况正在发生。

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

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

【讨论】:

  • 加入 t1 可以修复它,就像我怀疑的那样,但这仍然让我想知道为什么它在没有那条线的情况下会挂起(而且在某些情况下你不想加入,所以我仍然想弄清楚它出去)。从一次试验到下一次试验的输出(使用原始代码)的唯一差异是有时 4 也没有被打印出来。我认为这支持了主线程在 t1 之前结束的概念。而且我认为它在下一次执行时挂起的原因与 t1 在上一次运行中没有完成这一事实有关。
  • 我认为它应该每次都实例化一个新线程并丢弃旧线程(即使它仍然存在),所以我不完全理解为什么它会挂起。
  • 一旦主线程结束,进程退出。此时应消除所有t1 的痕迹。
  • 嗯...它似乎只在 t1 完成之前主线程退出后挂起。我认为 Adriano 将它作为控制台应用程序运行而不是使用即时窗口有一个很好的观点……我试过了,它再也没有挂起。 (为了清楚起见,我把它变成了一个控制台应用程序,在 Main 方法中我连续调用了 25 次 Go() 来模拟我正在做的事情,方法是从即时窗口调用它)。
猜你喜欢
  • 2015-03-02
  • 1970-01-01
  • 2019-05-08
  • 1970-01-01
  • 1970-01-01
  • 2010-09-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多