15

嗨,

我正在编写我的第一个 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;
    }
}

模块单定时器:

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;
}
4

3 回答 3

7

您有这个问题是因为静态数组中的计时器是在 中创建的Thread X,但在 中启动和停止Thread Y。这是不允许的,因为 Qt 依赖于超时计时器的线程亲和性。

您可以在同一线程中创建、启动停止或使用信号和槽来触发startstop操作计时器。信号和槽的解决方案有点问题因为你有nQTimer 对象(提示:你如何在位置启动计时器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上课
于 2014-10-20T12:19:16.907 回答
7

用于QTimer此目的并使用SIGNALSSLOT用于从不同线程启动和停止计时器。您可以从任何线程发出信号,并在创建计时器的线程中捕获它以对其进行操作。

既然你说你是 Qt 的新手,我建议你在继续之前先阅读一些教程,这样你就会知道 Qt 提供了什么,而不是最终试图重新发明轮子。:)

VoidRealms是一个很好的起点。

于 2014-10-20T10:43:22.030 回答
0

更改计时器概念后,我消除了错误。我不再使用我的 SingleTimer 模块。在 QTimer 之前我不会让超时,也许正因为如此我遇到了问题。现在我有一个循环 QTimer,它在插槽函数中每 100 毫秒超时,然后我将计算事件。在我的工作代码下面:

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;
            }
         }
    }
}
于 2014-10-21T06:04:10.140 回答