尝试重新启动线程时发生 ThreadStateException

Posted

技术标签:

【中文标题】尝试重新启动线程时发生 ThreadStateException【英文标题】:A ThreadStateException occures when trying to restart a thread 【发布时间】:2010-09-06 00:06:15 【问题描述】:

尝试重新启动线程时,有时我会收到 System.Threading.ThreadStateException。有问题的代码如下:

// Make sure the thread is done stopping
while (this.mThread.ThreadState == ThreadState.Running)
 
    Thread.Sleep(0);

// Respawn a thread if the current one is stopped or doesn't exist
if (this.mThread == null || this.mThread.ThreadState == ThreadState.Stopped)
 
    this.mThread = new Thread(new ParameterizedThreadStart(Monitor)); 
// Start the thread
if (check)
 
    this.mThread.Start(60000); 

else
   
    this.mThread.Start(0); 

所以有两个问题——这是正确的做事方式吗?是否有办法防止错误发生?

【问题讨论】:

【参考方案1】:

线程可能同时处于多个状态,因此 ThreadState 属性实际上是可能状态的位图。因此,仅用一种状态测试平等不会给您正确的结果。您需要执行以下操作:

if((mThread.ThreadState & ThreadState.Running) != 0)

然而,检查线程状态是错误的。我不完全清楚您要实现的目标,但我猜您正在等待线程终止,然后再重新启动它。在这种情况下,您应该这样做:

mThread.Join();
mThread = new Thread(new ParameterizedThreadStart(Monitor));
if(check)
    mThread.Start(60000);
else
    mThread.Start(0);

虽然如果您更详细地描述您要解决的问题,我几乎可以肯定会有更好的解决方案。等待线程结束只是为了再次重新启动它对我来说似乎没有那么有效。也许您只需要某种线程间通信?

约翰。

【讨论】:

【参考方案2】:

问题在于您的代码首先检查它是否应该创建一个新的线程对象,而另一段代码确定是否启动线程对象。由于竞争条件和类似情况,您的代码最终可能会尝试在现有线程对象上调用 .Start。考虑到您没有在 check 变量后面发布详细信息,因此不可能知道什么会触发此行为。

您应该重新组织您的代码,以保证 .Start 只在新对象上被调用。简而言之,您应该将 Start 方法放入与创建新线程对象的 if 语句相同的 if 语句中。

就个人而言,我会尝试重新组织整个代码,这样我就不需要创建另一个线程,而是将代码包装在循环内的线程对象中,以便线程继续运行。

【讨论】:

【参考方案3】:

抛出 ThreadStateException 是因为您试图启动一个未处于可启动状态的线程。最可能的情况是它已经在运行,或者它已经完全退出。

可能会发生一些事情。首先,线程可能已经从 Running 转换为 StopRequested,它还没有完全停止,所以你的逻辑不会创建一个新线程,你正在尝试启动一个刚刚完成运行或即将运行的线程完成运行(这两种状态都不是重新启动的有效状态)。

另一种可能是线程被中止。中止的线程进入 Aborted 状态,而不是 Stopped 状态,当然也不能重新启动。

真的,唯一可以“重新启动”的仍然活着的线程是被挂起的线程。您可能想改用这个条件:

if (this.mThread == null || this.mThread.ThreadState != ThreadState.Suspended)

【讨论】:

以上是关于尝试重新启动线程时发生 ThreadStateException的主要内容,如果未能解决你的问题,请参考以下文章

如果我们重新启动 Spring Boot 应用程序,正在运行的用户线程发生了啥?

启动多个线程并重新启动它们

尝试启动 Boost 线程时出错

为啥在 Google Colab 中重新启动运行时后 KMeans 的 silhouette_score 会发生变化?

尝试启动 MySQL 守护程序时发生超时错误。 CentOS 5

将表卸载到 s3 时,数据库会重新启动