中止的线程无法再次启动

时间:2015-03-18 10:13:30

标签: c# multithreading winforms

我遇到了问题而且不知道如何解决这个问题。我正在开始一个新的主题:

private void button_Click(object sender, EventArgs e)
{
        Thread thrd = new Thread(new ThreadStart(loadingScreenStart));
        thrd.Start();

        //setting some variables, entering some methods etc...

        thrd.Abort();
}

public void loadingScreenStart()
{
        splashScreen splashObj = splashScreen.GetInstance();
        Application.Run(splashScreen.GetInstance());
}

我有另一种形式:

private static splashScreen m_instance = null;
private static object m_instanceLock = new object();

public static splashScreen GetInstance()
{
        lock (m_instanceLock)
        {
            if (m_instance == null)
            {
                m_instance = new splashScreen();
            }
        }
        return m_instance;
}

这样可以正常工作,但是当我第二次按下按钮时,我得到一个例外,即无法访问被丢弃的对象。为什么以及如何解决这个问题?我的意思是在线程中止后,我再次点击按钮时创建一个新的。

5 个答案:

答案 0 :(得分:0)

它不是被丢弃的线程,而是splashScreen实例。你应该创建一个新的,而不是尝试重用旧的。

答案 1 :(得分:0)

Thread thrd = new Thread(new ThreadStart(loadingScreenStart));
thrd.Start();

//setting some variables, entering some methods etc...

thrd.Abort();

你为什么叫thrd.Abort()?你知道线程完成吗? 你必须等待线程完成。 并在这里使用双重检查

public static splashScreen GetInstance()
{
        if (m_instance == null)
        {
            lock (m_instanceLock)
            {
                if (m_instance == null)
                {
                   m_instance = new splashScreen();
                }
            }
        }
        return m_instance;
}

也许当你打电话给Run splashscreen时,它被处理掉了。尝试创建并将其捕获到字段并将其传递给您的方法。试试这个。

Task.Run(() => 
        var splashObj = splashScreen.GetInstance();
        Application.Run(splashObj);
    }));

答案 2 :(得分:0)

好的我以某种方式解决了它。不要认为这是一个很好的解决方案,但它确实有效。我只是隐藏SplashScreen的Form并检查线程是否已经运行,而不是中止线程。如果是,那么我只是显示表格。如果不是,我创建一个新实例。

答案 3 :(得分:0)

这太复杂而且不安全。如果你真的想用“闪屏”处理这个问题,为什么不试试这样的东西?

using (var splashScreenForm = SplashScreen.ShowSplashScreen())
{
  // Do your work
}

SplashScreen有这样的方法:

public static SplashScreen ShowSplashScreen()
{
  var form = new SplashScreen();

  new Thread(() => Application.Run(form)).Start();

  return form;
}

public override void Dispose(bool disposing)
{
  if (disposing)
  {
    if (InvokeRequired)
    {
      Invoke(() => base.Dispose(true));

      return;
    }

    base.Dispose(true);
  }
  else base.Dispose(disposing);
}

答案 4 :(得分:0)

再看看整个事情,我意识到这里还有另一个问题,这是完全错误的方向。

在您的button_Click活动中,您显然会做很多复杂的事情,需要花费很多时间。否则你不需要显示启动画面。但是,在事件处理程序中执行此操作本身并不是一个坏主意。你完全锁定了UI线程,Windows很快就会认为该窗口被挂起了#34;。它甚至无法重画!

所以你应该从完全相反的方向接近这个。在使用UI线程进行繁重的工作时,不要试图从另一个线程显示启动画面,只需将繁重的工作移动到另一个线程!然后,启动画面不需要任何异国情调,比如在另一个帖子中调用Application.Start()。只需一个简单的.ShowModal()即可。当其他线程完成其工作时,它只能在启动画面上调用.Close()

在设计良好的应用程序中,几乎不需要第二个UI线程。需要将繁重的工作转移到其他线程,而不是UI。

请注意,如果您想从另一个线程操纵UI,您需要做一些Invoke()的事情。在此处阅读更多内容:https://msdn.microsoft.com/en-us/library/system.windows.forms.control.invokerequired(v=vs.110).aspx