やあ、
私は最初のQtプログラムを書いていて、次の問題を抱えています:
QObject :: killTimer:別のスレッドからタイマーを停止することはできません
QObject :: startTimer:タイマーは別のスレッドから開始できません
私のプログラムは Canfestival Stack を使用しているため、CANOpenバスと通信します。 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;
}
静的配列のタイマーは_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
クラスは不要になりますこの目的でQTimer
を使用し、異なるスレッドからタイマーを開始および停止する目的でSIGNALS
およびSLOT
を使用します。任意のスレッドからシグナルを発信し、それに作用するタイマーを作成したスレッドでシグナルをキャッチできます。
あなたはQtを初めて使うと言っているので、先に進む前にいくつかのチュートリアルを実行して、Qtが何を提供する必要があるかを理解し、ホイールを再発明しようとしないことをお勧めします。 :)
VoidRealms が出発点として最適です。
タイマーの概念を変更した後、エラーを取り除きました。 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;
}
}
}
}