おそらく、タイトルの質問はあまり明確ではありません。 Windows7でQt5を使用しています。
ある時点のスレッド(QThread)、"process()"
関数/メソッドでは、このスレッドで使用しているQSslSocketに属する"encrypted()"
SIGNALを待つ必要があります。また、無限ループでブロックされないようにするために、QTimerを使用して"timeout()"
SIGNALを待つ必要があると思います...
私が今持っているものは:
_// start processing data
void Worker::process()
{
status = 0;
connect(sslSocket, SIGNAL(encrypted()), this, SLOT(encryptionStarted()));
QTimer timer;
connect(&timer, SIGNAL(timeout()), this, SLOT(timerTimeout()));
timer.start(10000);
while(status == 0)
{
QThread::msleep(5);
}
qDebug("Ok, exited loop!");
// other_things here
// .................
// end other_things
emit finished();
}
// slot (for timer)
void Worker::timerTimeout()
{
status = 1;
}
// slot (for SSL socket encryption ready)
void Worker::encryptionStarted()
{
status = 2;
}
_
まあ、明らかにそれは動作しません。それはそのwhileループに永遠にとどまります...
それで、質問は次のとおりです。この問題を解決する方法はありますか? "encrypted()"
SIGNALを待つにはどうすればいいですか?待機ループ/スレッドでスタックするのを避けるために、10秒としましょう。
ローカルイベントループを使用して、信号が発信されるのを待つことができます。
QTimer timer;
timer.setSingleShot(true);
QEventLoop loop;
connect( sslSocket, &QSslSocket::encrypted, &loop, &QEventLoop::quit );
connect( &timer, &QTimer::timeout, &loop, &QEventLoop::quit );
timer.start(msTimeout);
loop.exec();
if(timer.isActive())
qDebug("encrypted");
else
qDebug("timeout");
ここでは、encrypted
が発行されるか、タイムアウトに達するまで待機します。
非同期プログラミングでは、「待機」はアンチパターンと見なされます。物事を待つ代わりに、条件が満たされることに反応するようにコードを設計します。たとえば、コードを信号に接続します。
これを実装する1つの方法は、アクションを個別の状態にスライスし、各状態が開始されたときにいくつかの作業を行うことです。もちろん、作業量が自明でない場合は、ラムダの代わりに別のスロットを使用して、読みやすくします。
明示的なメモリ管理がないことに注意してください。 Qtクラスへの所有ポインターの使用は時期尚早な最適化であり、不必要な場合は避けるべきです。オブジェクトは、Worker
(またはその [〜#〜] pimpl [〜#〜] )の直接のメンバーにすることができます。
サブオブジェクトはすべて、ルートにWorker
を持つ所有権階層の一部である必要があります。そうすれば、Worker
インスタンスを別のスレッドに安全に移動でき、使用するオブジェクトがそれに続きます。もちろん、正しいスレッドでWorker
をインスタンス化することもできます-そのための簡単な idiom があります。スレッドのイベントディスパッチャーはワーカーを所有しているため、スレッドのイベントループが終了すると(つまり、QThread::quit()
を呼び出した後)、ワーカーは自動的に破棄され、リソースはリークしません。
_template <typename Obj>
void instantiateInThread(QThread * thread) {
Q_ASSERT(thread);
QObject * dispatcher = thread->eventDispatcher();
Q_ASSERT(dispatcher); // the thread must have an event loop
QTimer::singleShot(0, dispatcher, [dispatcher](){
// this happens in the given thread
new Obj(dispatcher);
});
}
_
ワーカーの実装:
_class Worker : public QObject {
Q_OBJECT
QSslSocket sslSocket;
QTimer timer;
QStateMachine machine;
QState s1, s2, s3;
Q_SIGNAL void finished();
public:
explicit Worker(QObject * parent = {}) : QObject(parent),
sslSocket(this), timer(this), machine(this),
s1(&machine), s2(&machine), s3(&machine) {
timer.setSingleShot(true);
s1.addTransition(&sslSocket, SIGNAL(encrypted()), &s2);
s1.addTransition(&timer, SIGNAL(timeout()), &s3);
connect(&s1, &QState::entered, [this]{
// connect the socket here
...
timer.start(10000);
});
connect(&s2, &QState::entered, [this]{
// other_things here
...
// end other_things
emit finished();
});
machine.setInitialState(&s1);
machine.start();
}
};
_
次に:
_void waitForEventDispatcher(QThread * thread) {
while (thread->isRunning() && !thread->eventDispatcher())
QThread::yieldCurrentThread();
}
int main(int argc, char ** argv) {
QCoreApplication app{argc, argv};
struct _ : QThread { ~Thread() { quit(); wait(); } thread;
thread.start();
waitForEventDispatcher(&thread);
instantiateInThread<Worker>(&myThread);
...
return app.exec();
}
_
QThread::started()
への接続は際どいことに注意してください。イベントディスパッチャーは、QThread::run()
内のコードが実行されるまで存在しません。したがって、スレッドが譲歩するのを待つ必要があります-これは、ワーカースレッドが1つまたは2つの譲歩内で十分に進行する可能性が非常に高いです。したがって、多くの時間を無駄にしません。
最近少し時間があり、調査をしました...
まあ、「 http://doc.qt.io/qt-5/qsslsocket.html 」を閲覧して、これを見つけました:
bool QSslSocket::waitForEncrypted(int msecs = 30000)
私の本当の恥に、私は前に気づかなかった... :(
必ずメガネを購入する必要があります(残念ながら、冗談ではありません!)
それをテストするために、それに応じてコードを修正します(月曜日@オフィス)。
動作する可能性はかなり高いです。あなたは何と言います:それは仕事をしますか?
はい、私の質問に答えるのはちょっと変ですが、たぶんIS解決策なので、共有することにしました:)