c++ - import qtimer
Qt5: ¿cómo esperar una señal en un hilo? (3)
Probablemente la pregunta del título no sea muy explícita. Estoy usando Qt5 en Windows 7.
En un hilo (QThread) en algún punto, en la función / método "run ()", debo esperar la "encrypted()"
SIGNAL "encrypted()"
pertenece a un QSslSocket que estoy usando en este hilo. También supongo que debería usar un QTimer y esperar un "timeout()"
SIGNAL para evitar ser bloqueado en un ciclo infinito ...
Lo que tengo ahora es:
// 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;
}
Bueno, obviamente no funciona. Permanece en ese ciclo while para siempre ...
Entonces, la pregunta es: ¿hay alguna manera de resolver este problema? ¿Cómo puedo esperar esa SEÑAL "encriptada ()" pero no más de, digamos 10 segundos, para evitar quedar atrapado en ese bucle / hilo de espera?
En la programación asincrónica, el "esperar" se considera un antipatrón. En lugar de esperar cosas, diseñe el código para reaccionar ante una condición que se cumpla. Por ejemplo, conecta el código a una señal.
Una forma de implementar esto es dividir sus acciones en estados separados y hacer algún trabajo cuando se ingrese cada uno de los estados. Por supuesto, si la cantidad de trabajo no es trivial, use una ranura separada en lugar de una lambda para mantener las cosas legibles.
Tenga en cuenta la ausencia de gestión de memoria explícita. El uso de punteros propios para las clases Qt es una optimización prematura y debe evitarse cuando sea innecesario. Los objetos pueden ser miembros directos del Worker
(o su PIMPL ).
Los subobjetos deben formar parte de la jerarquía de propiedad que tiene Worker
en la raíz. De esta forma, puede mover la instancia de Worker
a otro hilo de forma segura y los objetos que utiliza lo seguirán. Por supuesto, también podría crear una instancia del Worker
en el hilo correcto: hay un truco simple para eso:
void instantiateWorkerInThread(QThread * thread) {
QObject signalSource;
QObject * dispatcher = QAbstractEventDispatcher::instance(thread);
QObject::connect(&signalSource, &QObject::destroyed, dispatcher, [=](QObject*){
// this happens in the given thread
auto worker = new Worker;
connect(dispatcher, &QAbstractEventDispatcher::destroyed, worker, &QObject::deleteLater);
});
}
La implementación del trabajador:
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 = 0) : 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();
}
}
Puede usar un bucle de evento local para esperar a que se emita la señal:
QTimer timer;
timer.setSingleShot(true);
QEventLoop loop;
connect(sslSocket, SIGNAL(encrypted()), &loop, SLOT(quit()) );
connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
timer.start(msTimeout);
loop.exec();
if(timer.isActive())
qDebug("encrypted");
else
qDebug("timeout");
Aquí espera hasta que se emita encrypted
o llegue el tiempo de espera.
Tuve algo de tiempo estos días y investigué ...
Bueno, busqué " http://doc.qt.io/qt-5/qsslsocket.html " y encontré esto:
bool QSslSocket::waitForEncrypted(int msecs = 30000)
Para mi gran vergüenza, no me di cuenta antes ... :(
Definitivamente necesito comprar algunas gafas ( desafortunadamente , ¡no es una broma!)
Estoy dispuesto a modificar mi código en consecuencia para probarlo (el lunes en la oficina).
Casi todas las posibilidades de que funcione. ¿Qué dices: haría el trabajo?
Sí, es un poco raro responder mi propia pregunta, pero tal vez ES una solución, así que decidí compartir :)