15

ハイ、

私は最初の 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(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 はタイムアウト タイマーをスレッド アフィニティに依存しているため、これは許可されません。

同じスレッドで作成、停止を開始するか、シグナルとスロットを使用してタイマーのトリガーstartと操作を行うことができます。stopQTimerオブジェクトがあるため、シグナルとスロットのソリューションには少し問題がありnます(ヒント:どのようにしてタイマーを位置で開始します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この目的で使用し、異なるスレッドからタイマーを開始および停止する目的でSIGNALS使用します。SLOT任意のスレッドからシグナルを発行し、それに作用するタイマーを作成したスレッドでキャッチできます。

あなたは Qt に不慣れだと言っているので、先に進む前にいくつかのチュートリアルを実行して、Qt が提供するものを理解し、車輪の再発明を試みないようにすることをお勧めします。:)

VoidRealmsは良い出発点です。

于 2014-10-20T10:43:22.030 に答える
0

タイマーの概念を変更した後、エラーを解消しました。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;
            }
         }
    }
}
于 2014-10-21T06:04:10.140 に答える