סטנ*_*ונן 15 c++ qt multithreading timer wait
可能标题问题不是很明确.我在Windows7上使用Qt5.
在一个线程(QThread)中,在"process()"
函数/方法中,我必须等待"encrypted()"
属于我在此线程中使用的QSslSocket 的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;
}
Run Code Online (Sandbox Code Playgroud)
好吧,显然它不起作用.它永远停留在那个循环中......
所以,问题是:有没有办法解决这个问题?我怎么能等待那个"encrypted()"
SIGNAL但不要超过 - 比如10秒 - 以避免卡在那个等待循环/线程中?
Nej*_*jat 37
您可以使用本地事件循环来等待发出信号:
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");
Run Code Online (Sandbox Code Playgroud)
在此等待直到encrypted
发出或超时到达.
在异步编程中,"等待"被认为是反模式.而不是等待事物,设计代码以响应条件变得满足.例如,将代码连接到信号.
实现此目的的一种方法是将您的操作分割为单独的状态,并在输入每个状态时执行一些操作.当然,如果工作量不重要,请使用单独的插槽而不是lambda来保持可读性.
请注意,缺少显式内存管理.使用拥有指向Qt类的指针是一种过早的优化,应该在不必要的地方避免使用.对象可以是Worker
(或其PIMPL)的直接成员.
子对象必须都是Worker
根所在的所有权层次结构的一部分.这样,您可以安全地将Worker
实例移动到另一个线程,它使用的对象将遵循它.当然你也可以Worker
在正确的线程中实例化- 有一个简单的习惯用法.线程的事件调度程序拥有worker,因此当线程的事件循环退出时(即在调用之后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);
});
}
Run Code Online (Sandbox Code Playgroud)
工人的实施:
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();
}
};
Run Code Online (Sandbox Code Playgroud)
然后:
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();
}
Run Code Online (Sandbox Code Playgroud)
请注意,连接QThread::started()
将是racy:事件调度程序在内部某些代码QThread::run()
有机会执行之前不存在.因此,我们必须等待线程通过屈服来实现 - 这很可能使工作线程在一两次收益内得到足够的进展.因此,它不会浪费太多时间.
从 Qt 5.0 开始,QSignalSpy提供了一个等待方法。你把它连接到一个信号上,wait() 将阻塞直到信号触发。
QSignalSpy spy(SIGNAL(encrypted()));
spy.wait(5000); //wait until signal fires or 5 second timeout expires
Run Code Online (Sandbox Code Playgroud)