簡単な答え:非同期の実行から完了までのコードでブロックすることは想定されていません。aのすべてのイベントハンドラーとスロットの実装は、QObject
その役割を果たし、できるだけ早く戻ることになっています。忙しい待機や睡眠をすることは想定されていません。この線に沿ったより多くの怒りについては、MiroSamekのIhateRTOSesを参照してください。
上記に続くはるかに優れた実装については、代わりにこの回答を参照してください。以下に続くマクロのトリックは、Cで立ち往生している貧しい魂に任せるのが最善です。
少なくともコードの機能の観点から、正しい方法でそれを行う方法の例を添付しました。実際の実装が必要な場合は、Boostのスタックレスコルーチンをご覧ください。
マクロトリックはシンタックスシュガーです-それはテクニックをより口当たりの良いものにします(ブーストは私が以下よりもうまくやってくれます)。マクロを使用するか、メソッドを明示的に書き出すかは、あなた次第です。構文は、それを行うための「正しい方法」であると主張されているものではありません。このようなプリプロセッサのトリックを使用しているのは私だけではありません。欠落しているのは、ネストされた関数呼び出しと、内での実行から完了までの実行の複数の「スレッド」のサポートQObject
です。この例は、1つの「スレッド」と1つのレベルの非同期関数呼び出しのみのコードを示しています。Stackless Pythonは、これを論理的な結論に導きます。
非同期で作成すると、すべてのコードにこのパターンが表示されます。SLEEP
マクロは、コードを理解しやすくするためのシンタックスシュガーです。構文が圧倒されないC++のハッキーなマクロなしでそれを書くための本当にきれいな方法はありません。C ++ 11の時点でも、この言語にはyieldのサポートが組み込まれていません。C ++0xにyieldが追加されなかった理由を参照してください。。
これは本当にノンブロッキングコードです。「スリープ」しているときに定期的なタイマーイベントが発生することがわかります。この協調マルチタスクは、OSによって実行されるスレッド/プロセスの切り替えよりもはるかに低いオーバーヘッドであることに注意してください。16ビットのWindowsアプリケーションコードがこのように記述されたのには理由があります。それは、貧弱なハードウェアでも非常にうまく機能します。
このコードはを必要とせずQThread
、実際にはを使用しないことに注意してくださいQThread
。ただし、オブジェクトを優先度の高いスレッドに移動すると、遅延の広がりは小さくなります。
Qtタイマーの実装は、期間が「短い」場合、Windowsのタイマーティック期間を短縮するのに十分賢いです。以下に示すプラットフォーム固有のコードを使用できますが、お勧めできません。Qt 5では、Qt::PreciseTimer
タイマーを開始するだけです。Windows 8より前のシステムでは、ここでのパフォーマンスのために、消費電力とわずかに高いカーネルオーバーヘッドをトレードオフしていることに注意してください。Windows 8、OS X(xnu)、および最新のLinuxはティックレスであり、このようなパフォーマンスの低下に悩まされることはありません。
##および__LINE__(ポジショニングマクロとのトークン連結)を使用したCマクロの作成からの明確なプリプロセッサの悪用の方向性を認める必要があります。
マクロと同様に、SLEEP()
マクロを実装して、GOTO()
わかりやすいブロッキングコードスタイルで記述されているが、バックグラウンドで非同期である単純な有限状態マシンを使用できるようにすることもできます。状態の開始や終了などで実行されるアクションを実装するためのマクロを使用できますがENTER()
、LEAVE()
コードは完全にストレートコード化されたブロッキングスタイルの関数のように見えます。構文上のシュガーコーティングがないコードよりも、非常に生産的で、従うのが簡単であることがわかりました。YMMV。最終的には、UMLステートチャートに向かっているものがありますが、QStateMachine-based
実装よりもオーバーヘッド(実行時とコードテキストの両方)が少なくなります。
以下は出力です。アスタリスクは定期的なタイマーティックです。
doing something
*
*
*
*
*
*
*
*
*
*
slept, a=10
*
*
*
*
*
slept, a=20
*
*
slept, a=30
*
slept, a=40
#sleep.pro
QT += core
QT -= gui
TARGET = sleep
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += main.cpp
//main.cpp
#ifdef Q_WS_WIN
#include <windows.h>
#endif
#include <cstdio>
#include <QtCore/QTextStream>
#include <QtCore/QObject>
#include <QtCore/QBasicTimer>
#include <QtCore/QTimer>
#include <QtCore/QCoreApplication>
QTextStream out(stdout);
// this order is important
#define TOKENPASTE2(x,y) x ## y
#define TOKENPASTE(x,y) TOKENPASTE2(x,y)
#define SLEEP(ms) sleep(ms, &SLEEPCLASS::TOKENPASTE(fun, __LINE__)); } void TOKENPASTE(fun, __LINE__)() {
class Object : public QObject
{
Q_OBJECT
#define SLEEPCLASS Object // used by the SLEEP macro
public:
Object() {
QTimer::singleShot(0, this, SLOT(slot1()));
periodic.start(100);
connect(&periodic, SIGNAL(timeout()), SLOT(tick()));
}
protected slots:
void slot1() {
a = 10; // use member variables, not locals
out << "doing something" << endl;
sleep(1000, &Object::fun1);
}
void tick() {
out << "*" << endl;
}
protected:
void fun1() {
out << "slept, a=" << a << endl;
a = 20;
SLEEP(500);
out << "slept, a=" << a << endl;
a = 30;
SLEEP(250);
out << "slept, a=" << a << endl;
a = 40;
SLEEP(100);
out << "slept, a=" << a << endl;
qApp->exit();
}
private:
int a; // used in place of automatic variables
private:
void sleep(int ms, void (Object::*target)()) {
next = target;
timer.start(ms, this);
}
void timerEvent(QTimerEvent * ev)
{
if (ev->timerId() == timer.timerId()) {
timer.stop(); (this->*next)();
}
}
QTimer periodic;
QBasicTimer timer;
void (Object::* next)();
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Object o1;
#ifdef Q_WS_WIN
timeBeginPeriod(1); // timers will be accurate to 1ms
#endif
return a.exec();
}
#include "main.moc"