web-dev-qa-db-ja.com

Qtタイマーは別のスレッドから停止できません

やあ、

私は最初のQtプログラムを書いていて、次の問題を抱えています:

QObject :: killTimer:別のスレッドからタイマーを停止することはできません

QObject :: startTimer:タイマーは別のスレッドから開始できません

私のプログラムは Canfestival Stack を使用しているため、CANO​​penバスと通信します。 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::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;
}
13
Matt

静的配列のタイマーは_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クラスは不要になります
7
UmNyobe

この目的でQTimerを使用し、異なるスレッドからタイマーを開始および停止する目的でSIGNALSおよびSLOTを使用します。任意のスレッドからシグナルを発信し、それに作用するタイマーを作成したスレッドでシグナルをキャッチできます。

あなたはQtを初めて使うと言っているので、先に進む前にいくつかのチュートリアルを実行して、Qtが何を提供する必要があるかを理解し、ホイールを再発明しようとしないことをお勧めします。 :)

VoidRealms が出発点として最適です。

6
nnb

タイマーの概念を変更した後、エラーを取り除きました。 SingleTimerモジュールをもう使用しません。 QTimerの前は、タイムアウトを許可しません。そのため、おそらく問題が発生します。これで、スロット関数で100ミリ秒ごとにタイムアウトする循環QTimerができたので、イベントをカウントします。私の作業コードの下:

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;
            }
         }
    }
}
0
Matt