Qt跨线程发信号,一种是GUI线程?
在 Qt 中使用 moveToThread 将对象从一个线程移动到另一个线程意味着什么?即使在使用 moveToThread 之前,一切似乎都可以正常工作,它将对象从一个线程(GUI 线程)移动到另一个线程(工作),并且 Qt:connect 调用对象上适当的槽。
对象所在的位置(GUI 线程还是工作线程)有什么不同吗?
编辑: 我编写了一个小程序,但我不明白 QThread 如何与 Signal 和 slot 函数一起工作,如果您能用示例解释 moveToThread 的用途,我将不胜感激
#include <QtGui/QApplication>
#include <QPushButton>
#include <QHBoxLayout>
#include <QLineEdit>
#include <QString>
#include "mythread.h"
//GUI calls a thread to do some job and sub update the text box once it is done
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w;
QHBoxLayout * pH = new QHBoxLayout(&w);
QPushButton * pushButton = new QPushButton("asdad");
QLineEdit * lineEdit = new QLineEdit("AAA");
pH->addWidget(pushButton);
pH->addWidget(lineEdit);
w.setLayout(pH);
w.show();
MyThread thread;
qDebug("Thread id %d",(int)QThread::currentThreadId());
QObject::connect(pushButton,SIGNAL(clicked()),&thread,SLOT(callRun())) ;
QObject::connect(&thread,SIGNAL(signalGUI(QString)),lineEdit,SLOT(setText(QString)));
return a.exec();
}
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include <QMutex>
class MyThread : public QThread
{
Q_OBJECT
public:
MyThread();
public slots:
void callRun();
void run();
signals:
void signalGUI(QString);
private:
QMutex mutex;
};
#endif // MYTHREAD_H
#include "mythread.h"
#include <QDebug>
#include <QString>
#include <QMutexLocker>
MyThread::MyThread()
{
}
void MyThread::callRun()
{
qDebug("in thread");
if(!isRunning())
{
this->start(LowestPriority);
exec();
}
else
{
run();
}
}
void MyThread::run()
{
QMutexLocker fn_scope(&mutex);
static int a = 0;
++a;
qDebug("Thread id inside run %d",(int)QThread::currentThreadId());
this->sleep(3);
static QString number;
QString temp;
number += temp.setNum(a);
emit signalGUI(number);
}
What does it mean to move a object from one thread to another in Qt using moveToThread? Everything seems to work even before using moveToThread, which moves the object from one thread (GUI thread) to a another thread ( worked) and Qt:connect calls the appropriate slot on object.
Is there any difference because of where the object lives, GUI thread or the worker thread?
EDIT:
I made a small program, but I don't understand how QThread works along with Signal and slot function, I would appreciate if you could explain what is the use of moveToThread with the example
#include <QtGui/QApplication>
#include <QPushButton>
#include <QHBoxLayout>
#include <QLineEdit>
#include <QString>
#include "mythread.h"
//GUI calls a thread to do some job and sub update the text box once it is done
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w;
QHBoxLayout * pH = new QHBoxLayout(&w);
QPushButton * pushButton = new QPushButton("asdad");
QLineEdit * lineEdit = new QLineEdit("AAA");
pH->addWidget(pushButton);
pH->addWidget(lineEdit);
w.setLayout(pH);
w.show();
MyThread thread;
qDebug("Thread id %d",(int)QThread::currentThreadId());
QObject::connect(pushButton,SIGNAL(clicked()),&thread,SLOT(callRun())) ;
QObject::connect(&thread,SIGNAL(signalGUI(QString)),lineEdit,SLOT(setText(QString)));
return a.exec();
}
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include <QMutex>
class MyThread : public QThread
{
Q_OBJECT
public:
MyThread();
public slots:
void callRun();
void run();
signals:
void signalGUI(QString);
private:
QMutex mutex;
};
#endif // MYTHREAD_H
#include "mythread.h"
#include <QDebug>
#include <QString>
#include <QMutexLocker>
MyThread::MyThread()
{
}
void MyThread::callRun()
{
qDebug("in thread");
if(!isRunning())
{
this->start(LowestPriority);
exec();
}
else
{
run();
}
}
void MyThread::run()
{
QMutexLocker fn_scope(&mutex);
static int a = 0;
++a;
qDebug("Thread id inside run %d",(int)QThread::currentThreadId());
this->sleep(3);
static QString number;
QString temp;
number += temp.setNum(a);
emit signalGUI(number);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
查看 跨线程的信号和槽。如果您始终使用信号和槽与工作线程通信,则 Qt 会在需要时为您处理 moveToThread 并且您使用了正确的连接。
编辑:我猜这篇文章的作者看到了他的问题,因为他在实际创建线程之前在构造函数中调用了 start 。换句话说,不要盲目信任第三方代码。
编辑:为了回应您的评论,请查看 Mandelbrot 例如,在
MandelbrotWidget Class Implement
标头下:我相信这有点过时了,这里是有效的元类型 。由于跨线程的信号和槽使用排队连接,因此在大多数情况下您不必执行 moveToThread 调用。
编辑:
我将尝试用类似的示例来解释:
mythread.h:
mythread.cpp:
mylineedit.h
mylineedit.cpp
main.cpp:
单击按钮后的示例输出:
如您所见,运行线程与主 GUI 线程不同。另外,即使您传递了对 QString 的 const 引用,由于它跨越了线程边界,因此它会复制它。
我强烈鼓励您阅读线程和 QObject。
Take a look at Signals and slots across threads. If you always use signals and slots to communicate with the worker thread, Qt handles the moveToThread for you if it's needed and you used the correct connection.
Edit: I would guess the article's author was seeing his problem since he was calling start in the constructor before the thread was actually created. In other words, don't trust third-party code blindly.
Edit: In response to your comment, look at the Mandelbrot example, under the
MandelbrotWidget Class Implementation
header:I believe this is slightly outdated, here are the valid meta types. Since signals and slots across threads use queued connections, you should not have to do the moveToThread calls in most cases.
Edit:
I will try to explain things with a similar example:
mythread.h:
mythread.cpp:
mylineedit.h
mylineedit.cpp
main.cpp:
Sample output after clicking button:
As you can see, the run thread is different than the main GUI thread. Also, even though you pass a const reference to a QString, since it crosses thread boundaries it copies it.
I strongly encourage you to read Threads and QObject.
QThread::start()
方法创建线程并调用run()
实现。如果您想在线程上处理事件或接收信号,则必须在run()
实现中调用QThread::exec()
内部。您永远不应该显式调用run()
,也不应该在run()
之外调用exec()
。仅当插槽连接到连接类型不是
Qt::DirectConnection
的信号时,所有者线程才会产生影响。然后 Qt 将确保槽在所有者线程上运行,但为此所有者线程必须使用 QThread::exec() 运行事件循环。在这种情况下,调用myObj.moveToThread(myThread)
将确保myObj
槽在线程myThread
上运行。线程对象属于创建它的线程,而不是它管理的线程(以及 run 方法将运行的线程)。因此,当您将信号连接到线程对象的槽时,该槽将在创建该线程对象的线程中运行,除非您调用
moveToThread()
。The
QThread::start()
method creates the thread and calls yourrun()
implementation. If you want to handle events or received signals on the thread you have to callQThread::exec()
inside yourrun()
implementation. You should never callrun()
explicitly and you should never callexec()
outside ofrun()
.The owner thread makes a difference only when a slot is connected to a signal with the connection type other than
Qt::DirectConnection
. Then Qt will ensure that the slot runs on the owner thread, but for that the owner thread must be running an event loop withQThread::exec()
. In this case callingmyObj.moveToThread(myThread)
will ensure thatmyObj
slots run on the threadmyThread
.The thread object belongs to the thread where it was created, not on the thread that it manages (and where the run method will run). So when you connect a signal to a thread object's slot, that slot will run in the thread where the thread object was created unless you call
moveToThread()
.在线程之间移动对象时,您可以决定它属于哪个事件循环。当在线程内建立连接时,信号代码直接调用每个槽(必须等待它们完成)。跨线程边界的信号发送将信号调用置于事件循环上,让槽的线程在准备好时调用该槽。
在线程之间进行直接调用需要确保您的函数是可重入的。您还必须确保使用互斥体或信号量来保护您的数据,同时避免竞争条件。
在文章中,我猜测延迟是由于调用是直接的,即根本没有在后台处理(但我只浏览了文本)。
When moving an object between threads, you decide which event loop it belongs to. When making connections inside a thread, the signaling code directly calls each one of the slots (having to wait for them to finish). Signalling across thread boundaries places the signal call on the event loop, letting the slot's thread make the call to the slot when ready.
Making direct calls between threads requires you to make sure that your functions are reentrant. You must also make sure to protect your data using mutexes or semaphores and at the same time avoid race conditions.
In the article, I guess that the delay is due to the call being direct, i.e. not at all processed in the background (but I only skimmed the text).
新的线程对象被创建并且线程对象被移动到同一个线程。信号现在跨线程,连接类型都是队列,并且它按预期工作。
New thread object is created and the thread object is moved to the same thread. Signals are now across threads and connection type are both queue and it works as expected.
有些对象只能在所有者线程上使用。例如,如果您在一个线程中创建套接字对象,并且想要在另一个线程中发送和接收数据,则这是不可能的。因此,一种解决方案是将对象从一个线程移动到另一个线程并对其进行操作。
some objects only can be used on the owner thread. for example if you create and socket object in one thread and you want to send and recv data in another thread it is'nt possible. therefore one solution is to move your object from one thread to other and operate on it.