HY,
我正在编写我的第一个Qt程序,现在遇到麻烦:
QObject :: killTimer:无法从其他线程停止计时器
QObject :: startTimer:无法从其他线程启动计时器
我的程序将与CANOpen总线通信,因为我正在使用Canfestival Stack。 Canfestival将使用回调方法。为了检测通信中的超时,我设置了一个定时器功能(以某种方式像看门狗)。我的计时器包由“tmr”模块,“TimerForFWUpgrade”模块和“SingleTimer”模块组成。 “tmr”模块最初是C编程的,因此静态“TimerForFWUpgrade”方法将对其进行接口。 “tmr”模块将成为C程序固件更新包的一部分。
计时器将按如下方式工作。在发送消息之前,我将调用TMR_Set方法。然后在我的空闲程序循环中使用TMR_IsElapsed我们检查定时器下溢。如果TMR_IsElapsed我会做错误处理。如您所见,将连续调用TMR_Set方法并反复重新启动QTimer。
如果我启动程序,则会出现上述错误。你能告诉我我的概念是否有效吗?为什么会出现这种错误?我是否必须在主线程中使用其他线程(QThread)?
谢谢
马特
运行和空闲循环:
void run
{
// start communicate with callbacks where TMR_Set is set continously
...
while(TMR_IsElapsed(TMR_NBR_CFU) != 1);
// if TMR_IsElapsed check for errorhandling
....
}
模块tmr(C程序的接口):
extern "C"
{
void TMR_Set(UINT8 tmrnbr, UINT32 time)
{
TimerForFWUpgrade::set(tmrnbr, time);
}
INT8 TMR_IsElapsed(UINT8 tmrnbr)
{
return TimerForFWUpgrade::isElapsed(tmrnbr);
}
}
模块TimerForFWUpgrade:
SingleTimer* TimerForFWUpgrade::singleTimer[NR_OF_TIMERS];
TimerForFWUpgrade::TimerForFWUpgrade(QObject* parent)
{
for(unsigned char i = 0; i < NR_OF_TIMERS; i++)
{
singleTimer[i] = new SingleTimer(parent);
}
}
//static
void TimerForFWUpgrade::set(unsigned char tmrnbr, unsigned int time)
{
if(tmrnbr < NR_OF_TIMERS)
{
time *= TimerForFWUpgrade::timeBase;
singleTimer[tmrnbr]->set(time);
}
}
//static
char TimerForFWUpgrade::isElapsed(unsigned char tmrnbr)
{
if(true == singleTimer[tmrnbr]->isElapsed())
{
return 1;
}
else
{
return 0;
}
}
Module SingleTimer:
SingleTimer::SingleTimer(QObject* parent) : QObject(parent),
pTime(new QTimer(this)),
myElapsed(true)
{
connect(pTime, SIGNAL(timeout()), this, SLOT(slot_setElapsed()));
pTime->setTimerType(Qt::PreciseTimer);
pTime->setSingleShot(true);
}
void SingleTimer::set(unsigned int time)
{
myElapsed = false;
pTime->start(time);
}
bool SingleTimer::isElapsed()
{
QCoreApplication::processEvents();
return myElapsed;
}
void SingleTimer::slot_setElapsed()
{
myElapsed = true;
}
答案 0 :(得分:6)
为此目的使用QTimer
并使用SIGNALS
和SLOT
来启动和停止来自不同线程的计时器。您可以从任何线程发出信号,并在创建计时器的线程中捕获它以对其进行操作。
既然你说你是Qt的新手,我建议你在继续之前先阅读一些教程,这样你才能知道Qt提供什么,并且最终不会试图重新发明轮子。 :)
VoidRealms是一个很好的起点。
答案 1 :(得分:6)
您遇到此问题,因为静态数组中的计时器是在Thread X
中创建的,但在Thread Y
中已启动并停止。这是不允许的,因为Qt依赖线程亲和性来超时计时器。
您可以在同一个线程中创建,开始停止,也可以使用信号和插槽来触发定时器的start
和stop
操作。信号和插槽解决方案有点问题因为您有n
个QTimer对象(提示:如何在位置i
启动计时器?)
您可以做的是在
中的tmrnbr
位置创建并初始化计时器
TimerForFWUpgrade::set(unsigned char tmrnbr, unsigned int time)
{
singleTimer[tmrnbr] = new SingleTimer(0);
singleTimer[tmrnbr]->set(time);
}
由同一个线程执行。
此外,您不需要SingleTimer
课程。您正在使用Qt5,您已经拥有了所需的一切:
SingleTimer::isElapsed
确实是QTimer::remainingTime() == 0
; SingleTimer::set
真的是QTimer::setSingleShot(true); QTimer::start(time);
SingleTimer::slot_setElapsed
变得无用SingleTimer::SingleTimer
变得毫无用处,你不再需要SingleTimer
课了答案 2 :(得分:0)
我改变了我的计时器概念后就把错误拿走了。我不再使用我的SingleTimer模块了。在QTimer之前我不会让超时,也许是因为我遇到了问题。现在我有一个循环QTimer,它在插槽功能中每隔100ms超时,然后我将计算事件。在我的工作代码下面:
TimerForFWUpgrade::TimerForFWUpgrade(QObject* parent) : QObject(parent),
pTime(new QTimer(this))
{
connect(pTime, SIGNAL(timeout()), this, SLOT(slot_handleTimer()));
pTime->setTimerType(Qt::PreciseTimer);
pTime->start(100);
}
void TimerForFWUpgrade::set(unsigned char tmrnbr, unsigned int time)
{
if(tmrnbr < NR_OF_TIMERS)
{
if(timeBase != 0)
{
myTimeout[tmrnbr] = time / timeBase;
}
else
{
myTimeout[tmrnbr] = 0;
}
myTimer[tmrnbr] = 0;
myElapsed[tmrnbr] = false;
myActive[tmrnbr] = true;
}
}
char TimerForFWUpgrade::isElapsed(unsigned char tmrnbr)
{
QCoreApplication::processEvents();
if(tmrnbr < NR_OF_TIMERS)
{
if(true == myElapsed[tmrnbr])
{
return 1;
}
else
{
return 0;
}
}
else
{
return 0; // NOK
}
}
void TimerForFWUpgrade::slot_handleTimer()
{
for(UINT8 i = 0; i < NR_OF_TIMERS; i++)
{
if(myActive[i] == true)
{
myTimer[i]++;
if(myTimeout[i] < myTimer[i])
{
myTimer[i] = 0;
myElapsed[i] = true;
myActive[i] = false;
}
}
}
}