线程消失了?

5

点击按钮后,我会启动一个线程:

Thread myThread = new Thread(TestThread);
myThread.IsBackground = true;
myThread.Start();

线程方法内部:

// Start stopwatch
var watch = Stopwatch.StartNew();


// Our method
HelperMethods.Mymethod(
    "19-04-2015",
    "20-04-2015",
    Properties.Settings.Default.username,
    Properties.Settings.Default.password
);


// stop it
watch.Stop();

// Get number of ellapsed milliseconds
var elapsedMs = watch.ElapsedMilliseconds;


TimeSpan t = TimeSpan.FromMilliseconds(elapsedMs);
string answer = string.Format(
    "{0:D2}h:{1:D2}m:{2:D2}s:{3:D3}ms",
    t.Hours,
    t.Minutes,
    t.Seconds,
    t.Milliseconds
);


MessageBox.Show("Done " + answer);

昨天我启动了这个线程并离开了电脑(Windows+L)。 第二天,我等着看上面的消息框显示“完成”。 但即使 Mymethod 在那段时间内必须终止,它也没有出现。 Mymethod 中的整个代码都在 try/catch 内部,并记录发生在该方法内部的异常。奇怪的是,没有记录任何异常,表明我的程序意外终止或其他问题。 最后一条记录的消息(注意:我只记录错误)来自前一天晚上9点左右。 之后,没有任何迹象...... 我现在处于一个奇怪的情况...这里可能发生了什么? 有什么想法吗? 可悲的是,当我回来时,我终止了应用程序,无法检查 Mymethod 是否仍在运行,但它不应该在运行,因为它已经有足够的时间来完成。


4
如果消息框的所有者未指定,它不应该出现在工作线程中,这也是如此。 - vcsjones
3
请检查事件日志,未捕获的导致应用程序崩溃的异常会在那里记录。 - Martin Moser
1
你不能只是重新启动它吗?当你第二天回来时,如果没有任何消息,只需在你的IDE中点击“暂停”即可。 - Steffen Winkler
1
如果计算机处于睡眠模式,通常是静音的(风扇不会工作),并且需要几秒钟才能启动。如果计算机只是被锁定而没有进入睡眠模式,它应该像平常一样有噪音,并且当您移动鼠标时,唯一会发生的事情就是屏幕被打开。 - Viktor S.
@MattBurland:但是我的应用程序并没有像马丁所建议的那样崩溃。 - user4815230
显示剩余15条评论
3个回答

0

MessageBox.Show()应该在UI线程上调用,而不是从后台线程上调用。我建议您使用带有延续的Task

var task = Task.Factory.StartNew(TestThread);
task.ContinueWith(parent => 
{
    if(parent.Exception != null)
        MessageBox.Show("Done.");
    else
        MessageBox.Show("Exception occurred.");
}, TaskScheduler.FromCurrentSynchronizationContext());

以上代码将启动另一个线程中的方法,当该方法完成时,它会调度来自 ContinueWith() 的 lambda 在 UI 线程上执行。这样,对 MessageBox.Show() 的调用就不会破坏您的应用程序。

当然,不要忘记从 TestThread 方法中删除对 MessageBox.Show() 的调用。


我对C#还有点陌生,所以如果我能在不使用Task工厂等我不熟悉的东西的情况下找到错误就太好了。另外,有合理的怀疑问题出现在消息框之前。 - user4815230
请看这里:http://codeviewer.org/view/code:4fbe;我不想在这里发布它,因此提供链接(稍后我会删除它)。 - user4815230
@user300244,那个方法应该在日志文件中写入一些内容。你尝试过在调试器中运行它吗? - RePierre
上次即使有很多文件也没问题,刚才我遇到了这种奇怪的情况。 - user4815230
@user300244,首先想到的是您正在使用文件系统,这很容易出现错误 - 您是否有访问这些文件的权限,所有路径是否正确,这些文件是否被锁定等等?然而,这些问题应该使用AppendToLogFile进行记录。我能建议的就是在TestThread的开头设置断点并调试应用程序。 - RePierre
显示剩余4条评论

0
通常情况下,Windows 会在长时间没有用户输入时(默认为约 15-30 分钟)配置进入睡眠甚至休眠状态。
考虑到它整夜都没有使用,可能已经进入睡眠并停止了所有进程。因此,基本上线程在运行一段时间后已经被暂停,因为机器进入了睡眠模式。剩余的时间线程都没有工作。当您回来时,线程恢复,但应用程序很快就关闭了。换句话说,机器大部分时间都没有工作,线程没有时间运行到结束。而关闭应用程序实际上是完全停止了它。
下面是替代您的 HelperMethods.Mymethod 的代码,它在单独的后台线程中执行,就像您的情况一样:
while(i < 1000) { 
    Console.WriteLine(DateTime.Now); 
    i++; 
    Thread.Sleep(1000); 
}

当我运行它并将机器置于休眠状态时 - 这就是我得到的输出。
4/21/2015 6:00:45 PM
4/21/2015 6:00:46 PM
4/21/2015 6:00:47 PM
4/21/2015 6:00:48 PM
*** gap here. machine is in sleep, thread not working ***
4/21/2015 6:01:02 PM
4/21/2015 6:01:03 PM
4/21/2015 6:01:04 PM

此外,将方法命名为Mymethod是个不好的主意。方法名应该是具有描述性的。人们在不查看代码的前提下就能够理解这个方法在做什么。

谢谢你,当然这个方法还有另一个名字(我甚至在评论中发布了它的代码作为一个答案)。感谢你的建议,我会研究一下 - 但问题是我之前使用同样的软件长时间离开电脑,却没有观察到这样的问题...这就是为什么这次我感到困惑。 - user4815230
不确定锁和死锁在哪里检查?你认为像我上面提到的关闭硬件选项怎么样? - user4815230
硬件不应该是一个问题。只有当无法访问时,它才会出现故障。您的应用程序应该定期使用硬盘。这将不允许其关闭。关于锁 - 您的应用程序是否使用其他线程?如果是,它们是否共享某些数据(访问相同的对象/变量)?当您使用数据库时 - 是否存在任何异步操作?它们是否访问相同的表进行读写? - Viktor S.
你是指关于“20分钟后关闭硬盘”吗?关于线程,不是我的myMethod(您也可以参考其代码)是唯一在运行的东西,并且它会定期将数据写入数据库的不同表格;我不记得使用异步方法。 - user4815230
是的,我指的是“20分钟后关闭硬盘”选项。是的,我看到了你的方法代码,像Logs.Log1(currentTerminalName, currentDate);这样的方法可能会产生新的线程。但如果它们中没有线程-我就没有更多的想法了。最好的方法是记录每个操作并查看何时停止。也许,这样会有所帮助。 - Viktor S.
显示剩余6条评论

-1

MessageBox.Show("Done " + answer);

它会崩溃,导致您的线程消失。您应该将调用 MessageBox.Show 的操作移出线程。当线程完成时再调用。


如果消息框的所有者未指定,那么在跨线程中使用 MessageBox.Show 是合法的。 - vcsjones
这也是我所说的!它崩溃是因为跨线程问题,而链接中包含一篇文章,解释了如何管理此问题。 - Radin Gospodinov
@RadinGospodinov:所以你说问题是由于消息框引起的?就像我之前说的,很有可能在此之前(如果真的发生了)出现了问题,因为数据库中缺少一些数据。 - user4815230

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接