如何在 Qt 中创建 "deadman switch"?
How to make a "deadman switch" in Qt?
我想监控一个周期性的动作,这样我就可以在它停止时做一些事情。例如,切换到本地计时器以保持该操作继续进行,并在它再次启动备份时切换回主要来源。
我能想出的最好的理论例子是:
#define FRAME_INTERVAL_MSEC 33 // ~30Hz
bool periodFromUSB;
QTimer* myTimer;
void Processing::localTimeout()
{
//connected to myTimer->timeout();
if (periodFromUSB)
{
periodFromUSB = false;
myTimer->stop();
myTimer->setSingleShot(false);
myTimer->setInterval(FRAME_INTERVAL_MSEC);
myTimer->start();
}
processDMX();
}
void Processing::newFrame()
{
//called periodically from my USB driver
myTimer->stop();
if(!periodFromUSB)
{
periodFromUSB = true;
myTimer->setSingleShot(true);
myTimer->setInterval(FRAME_INTERVAL_MSEC * 2);
}
myTimer->start();
processDMX();
}
但无论我如何安排,当我的 USB 驱动程序为 运行 时,我总是会调用这两个函数。 (上面代码中的任何一个断点都会立即命中)
有没有更好的方法来做死人?
如果调用start(),定时器将重置为0并重新开始当前间隔。也就是说,只要在达到超时之前调用 newFrame() 插槽,就永远不会调用 localTimeout()。
您的代码将如下所示:
#define FRAME_INTERVAL_MSEC 33 // ~30Hz
bool periodFromUSB;
QTimer* myTimer;
void Processing::localTimeout()
{
//connected to myTimer->timeout();
if (periodFromUSB)
{
periodFromUSB = false;
}
processDMX();
}
void Processing::newFrame()
{
//called periodically from my USB driver
if(!periodFromUSB)
{
periodFromUSB = true;
}
myTimer->start(); // restarts current timer interval
processDMX();
// for debugging: display actual interval length in milliseconds:
static qint64 start = QDateTime::currentMSecsSinceEpoch();
static qint64 count = 0;
++count;
qint64 curr = QDateTime::currentMSecsSinceEpoch();
float msecsPerInterval = float(curr - start) / float(count);
qDebug() << "msecs per interval: " << msecsPerInterval;
}
void Processing::init()
{
myTimer = new QTimer();
connect(myTimer, &QTimer::timeout, this, &Processing::newFrame);
myTimer->setInterval(FRAME_INTERVAL_MSEC);
myTimer->start();
}
如果您的 localTimeout() 插槽仍然被调用,则您的 FRAME_INTERVAL_MSEC 太低了。
您可以使用我添加到 newFrame()
的调试代码来检查这一点。
这可能是因为:
- 您的 USB 驱动程序接收数据太少或
processDMX()
中的处理时间过长(如果processDMX()
的持续时间长于FRAME_INTERVAL_MSEC,则无法及时调用下一个槽)
我想监控一个周期性的动作,这样我就可以在它停止时做一些事情。例如,切换到本地计时器以保持该操作继续进行,并在它再次启动备份时切换回主要来源。
我能想出的最好的理论例子是:
#define FRAME_INTERVAL_MSEC 33 // ~30Hz
bool periodFromUSB;
QTimer* myTimer;
void Processing::localTimeout()
{
//connected to myTimer->timeout();
if (periodFromUSB)
{
periodFromUSB = false;
myTimer->stop();
myTimer->setSingleShot(false);
myTimer->setInterval(FRAME_INTERVAL_MSEC);
myTimer->start();
}
processDMX();
}
void Processing::newFrame()
{
//called periodically from my USB driver
myTimer->stop();
if(!periodFromUSB)
{
periodFromUSB = true;
myTimer->setSingleShot(true);
myTimer->setInterval(FRAME_INTERVAL_MSEC * 2);
}
myTimer->start();
processDMX();
}
但无论我如何安排,当我的 USB 驱动程序为 运行 时,我总是会调用这两个函数。 (上面代码中的任何一个断点都会立即命中)
有没有更好的方法来做死人?
如果调用start(),定时器将重置为0并重新开始当前间隔。也就是说,只要在达到超时之前调用 newFrame() 插槽,就永远不会调用 localTimeout()。
您的代码将如下所示:
#define FRAME_INTERVAL_MSEC 33 // ~30Hz
bool periodFromUSB;
QTimer* myTimer;
void Processing::localTimeout()
{
//connected to myTimer->timeout();
if (periodFromUSB)
{
periodFromUSB = false;
}
processDMX();
}
void Processing::newFrame()
{
//called periodically from my USB driver
if(!periodFromUSB)
{
periodFromUSB = true;
}
myTimer->start(); // restarts current timer interval
processDMX();
// for debugging: display actual interval length in milliseconds:
static qint64 start = QDateTime::currentMSecsSinceEpoch();
static qint64 count = 0;
++count;
qint64 curr = QDateTime::currentMSecsSinceEpoch();
float msecsPerInterval = float(curr - start) / float(count);
qDebug() << "msecs per interval: " << msecsPerInterval;
}
void Processing::init()
{
myTimer = new QTimer();
connect(myTimer, &QTimer::timeout, this, &Processing::newFrame);
myTimer->setInterval(FRAME_INTERVAL_MSEC);
myTimer->start();
}
如果您的 localTimeout() 插槽仍然被调用,则您的 FRAME_INTERVAL_MSEC 太低了。
您可以使用我添加到 newFrame()
的调试代码来检查这一点。
这可能是因为:
- 您的 USB 驱动程序接收数据太少或
processDMX()
中的处理时间过长(如果processDMX()
的持续时间长于FRAME_INTERVAL_MSEC,则无法及时调用下一个槽)