Thread.Join停止线程退出(或者也出现),但SpinWaiting让线程退出不是

时间:2014-10-17 00:10:36

标签: c# multithreading

我们遇到了一些需要定期针对API运行的函数以从设备获取信息的问题,我想出的解决方案使用新对象来运行线程,并且对象具有一些函数来告诉线程终止。该对象需要进行一些设置,运行定期命令并处理关闭。它还需要能够运行与periodic命令交错的其他命令。它在设置(启动,关闭和定期)时需要三个功能,您可以将委托传递给您想要交错的命令。启动和定期命令以及交错命令运行良好。

问题在于尝试停止操作并终止线程。

执行的线程函数看起来像

    private void InterleaverThread()
    {
        if (this.StartupFunction != null)
        {
            this.StartupFunction();
        }

        this.startUpFinished = true;

        while (!this.stop)
        {
            if (this.optCmd != null)
            {
                this.optCmdResult = this.optCmd();
                this.optCmdFinished = true;
            }

            if (this.stop)
            {
                break;
            }

            this.lastPeriodicCmdResult = this.PeriodicFunction();
        }

        if (this.ShutdownFunction != null)
        {
            this.ShutdownFunction();
        }

        this.startUpFinished = false;
    }

并且Stop命令看起来像

    public void StopInterleaver()
    {
        if (!this.IsRunning())
        {
            return;
        }

        this.stop = true;

        this.interleaverThread.Join();
        // SpinWait.SpinUntil(this.IsRunning);
    }

当使用Thread.Join()命令时,线程永远不会返回,但如果我使用SpinWait.SpinUntil() StopInterleaver命令在预期的时间范围内返回。 IsRunning()命令只检查线程IsAlive

    public bool IsRunning()
    {
        if (this.interleaverThread == null)
        {
            return false;
        }

        return this.interleaverThread.IsAlive;
    }

Thread来自System.Threading

我们无法弄清楚为什么.Join()不会返回但SpinWait.WaitUntil会返回。看起来他们应该做的事情基本相同。

1 个答案:

答案 0 :(得分:2)

我怀疑编译器正在优化你的循环而不是实际检查stop标志。也就是说,你有:

while (!this.stop)
{
    // do stuff
}

由于编译器发现stop的值在函数内部无法更改,因此只能将值缓存在寄存器中。

检查是否存在问题的一种方法是标记stop变量volatile,如下所示:

private volatile bool stop;
但是,这并不是一种特别强大的方法。处理事情的典型方法是使用CancellationToken。请参阅Cancellation

有关取消和示例的详细信息,请参阅Polling for Cancellation