Saltar al contenido

Qt5: ¿Cómo esperar una señal en un hilo?

Tenemos la contestación a esta duda, al menos eso pensamos. Si sigues con alguna interrogante puedes escribirlo en el apartado de preguntas y con gusto te ayudaremos

Solución:

Puede utilizar un bucle de eventos local para esperar a que se emita la señal:

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");

Aquí espera hasta encrypted se emite o se alcanza el tiempo de espera.

En la programación asincrónica, la “espera” se considera un anti-patrón. En lugar de esperar por las cosas, diseñe el código para que reaccione ante una condición que se cumpla. Por ejemplo, conecte el código a una señal.

Una forma de implementar esto es dividir sus acciones en estados separados y trabajar un poco cuando se ingresa a 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 una gestión de memoria explícita. El uso de punteros de propiedad a clases Qt es una optimización prematura y debe evitarse cuando sea innecesario. Los objetos pueden ser miembros directos de la Worker (o su PIMPL).

Los subobjetos deben ser parte de la jerarquía de propiedad que tiene Worker en la raiz. De esa forma, puede mover con seguridad el Worker instancia a otro hilo, y los objetos que utiliza lo seguirán. Por supuesto, también puede crear una instancia del Worker en el hilo correcto, hay un modismo simple para eso. El despachador de eventos del hilo es propietario del trabajador, por lo tanto, cuando el ciclo de eventos del hilo se cierra (es decir, después de invocar QThread::quit()), el trabajador se eliminará automáticamente y no se filtrarán recursos.

template 
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);
  );

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 = ) : 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();
  
;

Entonces:

void waitForEventDispatcher(QThread * thread) 
  while (thread->isRunning() && !thread->eventDispatcher())
    QThread::yieldCurrentThread();


int main(int argc, char ** argv) {
  QCoreApplication appargc, argv;
  struct _ : QThread  ~Thread()  quit(); wait();  thread;
  thread.start();
  waitForEventDispatcher(&thread);
  instantiateInThread(&myThread);
  ...
  return app.exec();

Tenga en cuenta que conectarse a QThread::started() sería picante: el despachador de eventos no existe hasta que algún código dentro QThread::run() tuvo la oportunidad de ejecutar. Por lo tanto, tenemos que esperar a que el subproceso llegue allí al ceder; es muy probable que esto haga que el subproceso de trabajo avance lo suficiente dentro de uno o dos rendimientos. Por lo tanto, no perderá mucho tiempo.

Tuve algo de tiempo estos días e hice una investigación …
Bueno, busqué “http://doc.qt.io/qt-5/qsslsocket.html” y encontré esto:

bool QSslSocket::waitForEncrypted(int msecs = 30000)

Para mi verdadera vergüenza, no lo había notado antes … 🙁
Definitivamente necesito comprar unas gafas (Desafortunadamente, ¡no es una broma!)
Estoy dispuesto a modificar mi código en consecuencia para probarlo (el lunes en la oficina).
Hay muchas posibilidades de que funcione.
[Late edit]:
Sí, esta es la solución que implementé en mi código final y funciona bien, así que decidí compartir 🙂

Aquí puedes ver las comentarios y valoraciones de los lectores

Eres capaz de asistir nuestra faena poniendo un comentario y valorándolo te damos la bienvenida.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *