In-depth understanding of QT Qthread
Before understanding Qthread, you need to understand the following Qthread class, Qthread has the following resources (excerpt from the QT 5.1 help document): In the above resources, this article focuses on the slot: start (); signal: Started (), finished () ; protected method: Run (), exec ();
Understanding QthreadQthread is very much out of line with commonly known threads (thread), in a process-oriented language where we create a thread and pass in a function name that represents the specific code that the thread executes (1). Figure 1. The thread we usually understand but Qthread does not have a thread-specific code, Qthread is just an interface to provide the operating system with a "handle" for thread scheduling. This "handle" is the entrance to the Qthread (shown in 2). Figure 2. Qthread is an "object-oriented" Qthread, which can be a slot function or an event handler, but because it is dispatched by the system, the "exact" execution time of these functions is unpredictable. The exit of the Qthread is the finished () signal. As a thread, Qthread would not hesitate to create a run space for himself, a separate thread of execution, a new threading, but flipping through the resources owned by Qthread, we could not find the place to pass in the function name, so it seems as if we could not provide specific execution code for this newly created thread. Many people think of the run () method, thus inheriting the Qthread function and writing their own code in the Run () method, often requiring the run () method not to exit immediately, so join the loop body and the Wait () method, and sometimes call exec () to plug in response to an event. However, this practice is not recommended, and there are already articles stating "Qthread was designed and are intended to being used as an interface or a control point to an operating Syste M thread, not as a place-to-put code that is want to run in a thread. "See also:
>.
So, Qthread really can't execute a specific code? If not, how do you deliver the program that will be executed in the new thread to Qthread? The answer is the Movetothread () method. Any subclass that is based on the Qobject class has this method. An object isAfter moveto to a new thread, it has slot functions and event handlers that are moved into the same run space as the new thread, becoming the interface between the new thread and the operating system, which becomes the portal for the new thread. Slot functions and event handlers are executed in the new thread space when there is a signal connected to the slot or an event that matches it. If that's all, then it's easy to get another problem, the example of the connection above. We'll explain it in detail here. The procedure is as follows:
123456789101112131415161718 |
class
MyThread :
public
QThread
{
public
:
MyThread()
{
moveToThread(
this
);
}
void
run();
signals:
void
progress(
int
);
void
dataReady(QByteArray);
public
slots:
void
doWork();
void
timeoutHandler();
};
|
What is the problem with the above procedure? As the text says: "We ' re telling the thread to run code" in itself ". We ' re also doing this
beforeThe thread is running as well. Even though this seems to work, it's confusing, and not how qthread is designed to being used (all of the functions in Qthre Ad were written and intended to is called from the creating thread, not the thread that Qthread starts). " To sum up, the problem has two points: 1. Movetothread () in the constructor, at which point Mythread has not yet started to run; 2. After moving mythread to its own space to run, we lose the reference to Mythread. The above two points can easily lead to very deadly problems. As we can see, we are a bit too "unscrupulous" to let the code execute in a new thread. The root cause of the above problem is that it is not fully understood that Qthread is just the essence of an interface. So how do you properly get the program to execute in a new thread? The answer is to moveto the objects that need to be run in the new thread to Qthread instead of inheriting Qthread and moveto themselves into the new thread space. Therefore, we propose the following important principles of applying qthread.
Qthread Application principles:1.QThread is just the interface of the system execution thread, not for writing code; 2. Objects created in the context of the current thread (such as thread A) belong to the current thread, and other threads (such as: Threads B, C, D ...). You cannot manipulate objects that belong to the current thread (such as thread A); 3. Objects based on the object class in the current thread (such as thread A) can be moved to other threads (such as: Threads B, C, D ...). 4. Object-based objects in the current thread (for example, thread a) are moving to other threads (such as: Threads B, C, D ...). The target thread (e.g. threads B, C, D ...) is required to execute. ) has already started running; the object class-based objects are moved to other threads (such as threads B, C, D ...) if the current thread (for example: Thread a) is moving. ), the object can only be used by the target thread (for example: Threads B, C, D ...). ) is responsible for release. In addition, when connecting a signal to a slot owned by an object that is moveto to a new thread, you need to be aware of the way you connect.
Note:The signals and slots are connected in the following ways: Qt::autoconnection, Qt::D irectconnection, Qt::queuedconnection and Qt::blockingqueuedconnection. Qt::autoconnection: The Qt is selected based on the thread in which the object resides::D irectconnection or QT::QUEUEDCONNECTION;QT::D irectconnection: For the same thread, Equivalent to a direct function call, the slot function is executed before returning; Qt::queuedconnection: for different threads, a queue is created and the slot function returns immediately without waiting for the signal in the queue to execute; Qt: Blockingqueuedconnection: It is also used for different threads, but it is equivalent to a function call, because it is not possible to return until the slot function has finished executing.
Example:Here, an example of applying qthread is provided, which opens a serial port for receiving data, but in order to take into account the UI response to the user, a separate thread is created for the serial receiver program. Because the serial port object is moveto into a new thread, the serial port cannot be closed in the UI thread, so the Qthread finished () signal is used. This is just an example, and the code is written with more emphasis on presentation than the other. The project organization for the example is as follows: The form in the Uiwindow.ui file is in the initialization state. The contents of the Serial.pro file are as follows:
--------------------------------------------------------------------------
#-------------------------------------------------
#
# Project created by Qtcreator 2014-07-18t15:41:22
#
#-------------------------------------------------
QT + + core GUI
GreaterThan (Qt_major_version, 4): QT + = Widgets
GreaterThan (Qt_major_version, 4) {
QT + = Widgets SerialPort
} else {
Include ($ $QTSERIALPORT _project_root/src/serialport/qt4support/serialport.prf)
}
TARGET = Serial
TEMPLATE = App
SOURCES + = Main.cpp\
Uiwindow.cpp \
Serial.cpp
HEADERS + = uiwindow.h \
Serial.h
FORMS + = Uiwindow.ui
--------------------------------------------------------------------------
The contents of the Serial.h file are as follows:
--------------------------------------------------------------------------
#ifndef Serial_h
#define Serial_h
#include <QObject>
#include <QtSerialPort/QSerialPort>
Class Serial:public Qobject
{
Q_object
Public
Explicit Serial (Qobject *parent = 0);
~serial (void);
Qserialport *port;
Signals:
Public Slots:
void ReadData (void);
void threadstarted (void);
void threadfinished (void);
};
#endif//Serial_h
--------------------------------------------------------------------------
The contents of the Serial.cpp file are as follows:
--------------------------------------------------------------------------
#include "serial.h"
#include <QMessageBox>
#include <QDebug>
#include <QThread>
Serial::serial (Qobject *parent):
Qobject (parent)
{
Port = new Qserialport ();
Port->setportname ("COM1");
if (!port->open (Qserialport::readwrite))
{
Qmessagebox wrrmsg;
Wrrmsg.setinformativetext ("Unable to open the serial port");
Wrrmsg.show ();
Wrrmsg.exec ();
}
Port->setbaudrate (qserialport::baud19200,qserialport::alldirections); 19200,n,8,1
Port->setdatabits (qserialport::D ata8);
Port->setstopbits (Qserialport::onestop);
Port->setparity (qserialport::noparity);
Port->setflowcontrol (Qserialport::noflowcontrol);
Connect (port, SIGNAL (Readyread ()), this, SLOT (ReadData ()), Qt::D irectconnection); Note that the real execution port is in the same thread as Serial, so use Qt::D irectconnection.
}
Serial::~serial (void)
{
}
void Serial::readdata (void)
{
Qdebug () << "Reading Data ... ID is: "<< qthread::currentthreadid ();
Port->clear (qserialport::alldirections);
}
void serial::threadstarted (void)
{
Qdebug () << "Thread has started ... ID is: "<< qthread::currentthreadid ();
}
void serial::threadfinished (void)
{
Qdebug () << "Closing COM Port ... ID is: "<< qthread::currentthreadid ();
if (Port->isopen ())
{
Port->close (); Close the serial port.
}
}
--------------------------------------------------------------------------
The contents of the Uiwindow.h file are as follows:
--------------------------------------------------------------------------
#ifndef Uiwindow_h
#define Uiwindow_h
#include <QMainWindow>
#include <QThread>
#include "serial.h"
Namespace Ui {
Class UIWindow;
}
Class Uiwindow:public Qmainwindow
{
Q_object
Public
Explicit UIWindow (Qwidget *parent = 0);
~uiwindow ();
Private
Ui::uiwindow *ui;
Qthread Serialthread;
Serial *serial;
};
#endif//Uiwindow_h
--------------------------------------------------------------------------
The contents of the Uiwindow.cpp file are as follows:
--------------------------------------------------------------------------
#include "Uiwindow.h"
#include "Ui_uiwindow.h"
#include <QDebug>
Uiwindow::uiwindow (Qwidget *parent):
Qmainwindow (parent),
UI (New Ui::uiwindow)
{
UI->SETUPUI (this);
Qdebug () << "UI thread ID is:" << qthread::currentthreadid ();
serial = new serial ();
Connect (&serialthread, SIGNAL (Started ()), Serial, SLOT (threadstarted ()), qt::queuedconnection); Note that Serialthread and serial are not in the same thread, so use qt::queuedconnection.
Connect (&serialthread, SIGNAL (finished ()), Serial, SLOT (threadfinished ()), Qt::D irectconnection); The Serialthread finished () signal is executed in a new thread, so Qt is used here::D irectconnection.
Serialthread.start (qthread::highestpriority); Open thread, the serial receive thread has higher priority.
Serial->movetothread (&serialthread); Move the serial accept object to the new thread.
Serial->port->movetothread (&serialthread); The port used for the receive is moved into the new thread.
}
Uiwindow::~uiwindow ()
{
if (serialthread.isrunning ())
{
Serialthread.exit (); Ends the thread.
Serialthread.wait ();
/*while (!serialthread.isfinished ())
{
;
}*/
}
Delete UI;
}
--------------------------------------------------------------------------
http://blog.csdn.net/desert187/article/details/37932999
In-depth understanding of QT Qthread