尝试重新启动线程时发生ThreadStateException
尝试重新启动线程时,有时会收到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); }
因此,有两个问题是这是正确的做事方式吗,有没有办法防止错误发生?
解决方案
回答
抛出ThreadStateException异常是因为我们试图启动一个不在可启动状态下的线程。最有可能的情况是它已经在运行,或者已经完全退出。
可能有几件事可能正在发生。首先,该线程可能已从"运行"转换为"停止请求",但尚未完全停止,因此逻辑不会创建新线程,而我们正在尝试启动一个刚刚运行完毕或者即将执行的线程。完成运行(都不是重新启动的有效状态)。
另一种可能性是线程被中止。中止的线程进入"中止"状态,而不是"已停止"状态,当然也对重启无效。
确实,唯一可以被"重新启动"但仍处于活动状态的线程是被挂起的线程。我们可能要使用以下条件:
if(this.mThread == null || this.mThread.ThreadState!= ThreadState.Suspended)
回答
线程可能一次处于多个状态,因此ThreadState属性实际上是可能状态的位图。因此,仅用一种状态测试相等性将不会给我们正确的结果。我们将需要执行以下操作:
if((mThread.ThreadState & ThreadState.Running) != 0)
但是,检查线程状态是做任何事情的错误。我尚不清楚我们要实现的目标,但我猜我们正在等待线程终止之后再重新启动它。在这种情况下,我们应该执行以下操作:
mThread.Join(); mThread = new Thread(new ParameterizedThreadStart(Monitor)); if(check) mThread.Start(60000); else mThread.Start(0);
尽管如果我们要描述问题,但我们尝试更详细地解决,我几乎可以肯定会有更好的解决方案。在我看来,等待一个线程结束只是为了重新启动它似乎并没有那么高效。也许我们只需要某种线程间通信?
约翰。
回答
问题是我们拥有先检查是否应创建新线程对象的代码,以及确定是否可以启动线程对象的另一段代码。由于竞争条件和类似原因,代码可能最终尝试在现有线程对象上调用.Start。考虑到我们没有将详细信息发布在check变量后面,因此无法知道可能触发此行为的原因。
我们应该重新组织代码,以确保仅在新对象上调用.Start。简而言之,我们应该将Start方法放入与创建新线程对象相同的if语句中。
就个人而言,我将尝试重新组织整个代码,从而无需创建另一个线程,而是将代码包装在线程对象内的循环内,以便线程继续运行。