如何以线程安全的方式检查一个线程的状态?

时间:2015-07-15 22:33:23

标签: c# multithreading

背景:

在调试应用程序时,我遇到了这个函数

boolean IsThreadGood(Thread t)
{
    return t.IsAlive && t.ThreadState == ThreadState.Running || t.ThreadState == ThreadState.WaitSleepJoin;
}

我认为这是一个错误,因为在return语句中发生的逻辑比较不是原子的,因此我认为Thread t可以在表达式执行时改变状态。为了检查这个想法,我将代码更改为以下代码,以便我可以放置断点:

bool IsThreadGood(Thread t)
{
    if (t.IsAlive)
    {
        if (t.ThreadState == ThreadState.Running)
        {
            return true;
        }
        if (t.ThreadState == ThreadState.WaitSleepJoin)
        {
           return true;
        }
    }
    return false;
}

我在内部if语句上放置了断点,很快就看到了我怀疑的内容。当代码到达第一个断点时,线程t的ThreadState为WaitSleepJoin,当我将代码转移到下一个if语句时,线程t已经切换状态并且线程状态为Running,因此两个测试都失败并且当方法返回false时应该回归真实。

我的问题:

我怎样才能以线程安全的方式检查来自另一个线程的线程的状态?

我的想法和我研究的内容:

  1. 如果我能使声明成为原子,那就行了。我用Google搜索了一些诸如“如何在c#中创建一个原子语句”并得到了很多涉及锁的结果 - 而不是我想要的东西,因为据我所知,锁不会使代码成为原子。

  2. 如果我可以从执行该方法的线程挂起Thread t,那么我可以安全地检查它的状态。我在这里找到的是过时的功能Suspend and Resume。 Microsoft强烈建议不要使用这些。

  3. 以某种方式更改线程t以实现同步。不是一种选择。代码是可重用的代码,已被不同的客户端以不同的方式重用,而Thread t是客户端代码。无法更改所有客户。

  4. 我不是多线程大师,所以如果我的任何假设不正确或者我对多线程的理解不正确,请随时指出。

3 个答案:

答案 0 :(得分:3)

我很确定状态为RunningWaitSleepJoin的线程不能无效。所以你可以得到状态(这是一个原子操作),然后检查这两个值:

boolean IsThreadGood(Thread t)
{
    ThreadState state = t.ThreadState;
    return state == ThreadState.Running || state == ThreadState.WaitSleepJoin;
}

请注意,the documentation明确指出您应该仅将线程状态用于调试目的,而不是用于同步:

  

线程状态仅在调试方案中有用。您的代码永远不应该使用线程状态来同步线程的活动。

由于您对原子操作感兴趣,我怀疑您是否希望将其用于调试目的(否则您不需要关心它是否超精确)。所以你应该考虑以不同的方式解决你的实际问题。

答案 1 :(得分:1)

这可能无法正常工作。线程可能处于最后一条指令,您的支票将错过接近并保证退出。线程必须与您合作。您需要在更高级别进行同步。我无法建议如何,因为我不知道应用程序的功能。提出一个包含详细信息和代码的新问题。

注意,t.IsAlive && t.ThreadState == ThreadState.Running || t.ThreadState == ThreadState.WaitSleepJoin错过了||运算符周围的大括号。并不重要,因为必须抛弃此代码。

state == ThreadState.WaitSleepJoin应该完成什么?这种状态可能会发生虚假,因为许多库可能会进入该状态。这一切似乎都是假的。

作为一种解决方法,您可以实现一个监视程序线程:

while (true)
 DetectExit();
 Sleep(100);

答案 2 :(得分:0)

方法Thread.Join(int millisecondsTimeout)可用于安全地测试线程是否已完成。当线程不再处于活动状态时,它返回true。

 // 0 == don't wait.
 if (thread.Join(0))
 {
    // remove thread from the list
 }

出于显而易见的原因,应该从另一个线程调用它。