我们遇到了一些需要定期针对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
会返回。看起来他们应该做的事情基本相同。
答案 0 :(得分:2)
我怀疑编译器正在优化你的循环而不是实际检查stop
标志。也就是说,你有:
while (!this.stop)
{
// do stuff
}
由于编译器发现stop
的值在函数内部无法更改,因此只能将值缓存在寄存器中。
检查是否存在问题的一种方法是标记stop
变量volatile,如下所示:
private volatile bool stop;
但是,这并不是一种特别强大的方法。处理事情的典型方法是使用CancellationToken
。请参阅Cancellation。
有关取消和示例的详细信息,请参阅Polling for Cancellation。