找出一个线程是不是已经开始?

Posted

技术标签:

【中文标题】找出一个线程是不是已经开始?【英文标题】:Find out if a thread has started?找出一个线程是否已经开始? 【发布时间】:2012-09-12 19:00:09 【问题描述】:

我有以下代码:

var x = new Thread(new ThreadStart(Delegate));
x.Start();

这将创建一个新线程并启动它。

我如何才能检测到线程 X 已经开始执行而没有立即执行 do while 循环?

【问题讨论】:

IsAlive 怎么样?还是我误会了? 对了,代码应该有错误。您不能从 Start() 方法分配 x 因为它是无效的 :) 不用担心,我想我们都理解您的问题 知道这个有用吗?我可以理解为什么知道新线程是否已经到达某些初始化代码的末尾可能很有用,但这似乎不是您想要的? 修复了我的代码,使其正确。我需要知道这一点,因为我正在创建将在我的应用程序中运行的“服务”(最有可能是错误的术语)线程。很难用一句话来解释它到底会做什么。我确实需要知道线程是否正在运行。 我完全不确定这些信息在用户级别是否可用。当任何这样的线程状态被返回时,它已经过时了——线程状态很可能已经改变了。 【参考方案1】:

使用信号量、互斥体或 Auto/ManualResetEvent。

代码

//Initialize semaphore, set it to BLOCK
ManualResetEvent sema = new ManualResetEvent(false);

void Main()

    var x = new Thread(Delegate);
    //Request the system to start the thread.
    //This doesn't mean the CPU will immediately run Delegate method
    //but eventually it will do
    x.Start(sema);

    //Stop here and don't do anything on this thread until the semaphore is FREE
    sema.WaitOne();

    [continued main thread]


void Delegate(Semaphore sema)
    //Unblock the semaphore
    sema.Set(1);
    [your code here]

深入解释

多线程背后的原则之一是非确定性。如果您不使用正确的技术,如上所述,您无法预测在多个线程中完成的操作的行为如果您有这样的方法

void Main()

    A();
    B();
    C();

那么你确定 B 永远不会在 A 之前或 C 之后执行。这同样不适用于多线程。

void Main()

    new Thread(A).Start();
    new Thread(B).Start();
    new Thread(C).Start();

    D();

您确定运行 B 的线程在运行 A 的线程之后是 started,但在多线程中这意味着不同的东西。在 MSDN 和每本编程书籍中,启动线程仅仅意味着请求操作系统在内核中分配适当的设施以支持多线程。如果这样做了(线程被正确创建并安排执行),则该方法返回而不会出错。操作系统可能会以任意顺序运行三个线程,具体取决于多种因素。

因此,如果您将它们调试到控制台(认为每个都执行Console.WriteLine("Hello, I'm thread A/B/C"),您可以在不同的执行中获得任何顺序:A,B,C;A,C,B;B,C,A 等等。

所以你现在想确定,但真的,真的确定,一个特定的或每个线程在运行 D 之前已经真正启动了。事实上,在许多单核 CPU 的情况下,操作系统应该运行 @每个线程之前的 987654329@ 方法。这也是不可预知的!所以在无法预测 A、B 和 C 什么时候运行之后,你就无法预测 D 什么时候运行了!!

显式同步是一种强制暂停代码执行并等待事件发生的技术。信号量释放所描述的事件取决于上下文,所以在你的情况下,你只是告诉主线程“等待委托开始,然后做任何你想做的事情”:)

替代的、低效的方法

使用信号量只是通过无限循环执行以下操作的一种有效方法

volatile bool threadStarted = false;

void Main()

    var x = new Thread(Delegate);
    x.Start();

    while (!threadStarted);
    [continued main thread]


void Delegate(Semaphore sema)
    threadStarted = true;
    [your code here]

使用信号量不会简单地浪费 CPU 来不断检查某个标志是低还是高

【讨论】:

你也可以在这里使用Auto/ManualResetEvent 我对你的代码有点困惑。是的,它有效,但我不明白如何,您能否更新您的代码,以便我和其他不理解的人可以从中学习?我不明白这些对象是什么,它们做什么,以及方法调用做什么。感谢您的回答和努力! 将 ManualResetEvent 比喻为交通信号灯,默认为“红色”。线程启动,接收该信号,而主程序现在在该交通灯上执行“.WaitOne”,只要其“红色”。线程通过调用 .Set(1) 方法将委托代码中的信号更改为“绿色”(再次比喻地)。 “WaitOne”看到了变化,灯现在是“绿色”的,并且继续 - 保证它只有在新线程实际启动后才会继续。 帖子已编辑。我希望这会是一场精彩的讲座。反正我不在的时候+1 给@DavidW【参考方案2】:

在最基本的层面上,你可以尝试:

if (((Thread)x).ThreadState==ThreadState.Running)
   // do something interesting

【讨论】:

虽然这将告诉线程是否正在运行,但 ThreadState 文档明确指出它不应该用于同步线程。如果 Landin Martens 正在调试,那么这很好,否则,最好使用 djechelon 的答案。 如果设置了其他标志(例如背景)将不起作用。您只需要测试标志 Running。【参考方案3】:
x.ThreadState == System.Threading.ThreadState.Running

【讨论】:

如果设置了其他标志(例如背景)将不起作用。您只需要测试标志 Running。【参考方案4】:

您可以使用Thread.ThreadState 属性来查找其状态。

【讨论】:

【参考方案5】:

最简单的方法,假设线程是长寿命的,就是检查Thread.IsAlive。

【讨论】:

我想我必须不同意。调用 start 后 Thread.IsAlive 设置为 true,但不提供线程是否已被 CPU 调度的信息

以上是关于找出一个线程是不是已经开始?的主要内容,如果未能解决你的问题,请参考以下文章

判断线程是不是已经启动

找出从后台线程访问的 winforms 控件

找出应用程序是不是已经初始化?

知道未来是不是已经开始

从零开始山寨Caffe·肆:线程系统

在java多线程程序中,怎样实时找出处于等待(阻塞)状态线程、进程的个数。