Table of contents
Chapter 1 Communication Mechanism Between Threads
1.1 Common Mechanisms for Communication Between Threads
1.2 The solution to the imbalance between the sending data thread and the receiving data thread
Chapter 2 Communication Between Objects: Signal and Slot Communication
Chapter 3 Inter-Thread Communication: Transferring Data Between Threads
Chapter 1 Communication Mechanism Between Threads
1.1 Common Mechanisms for Communication Between Threads
Qt provides a variety of inter-thread communication mechanisms, including:
- Signal slot mechanism: Through signal slot connection, asynchronous communication can be performed between different threads. The sender transmits the signal, and the receiver receives the signal through the slot function and executes the corresponding logic. When using the signal-slot mechanism, Qt automatically handles data transfer and thread safety between threads .
exec()
The method of QThreadquit()
: By inheriting the QThread class, rewritingrun()
the method to define the execution logic of the thread, and thenexec()
starting the event loop of the thread by calling the method. Terminates the thread's event loop by callingquit()
a method.finished()
Signals and methods of QThreadQThread::wait()
: When a QThread object finishes executing, it emitsfinished()
a signal. You can realize the synchronous waiting of threads by connecting this signal.- QtConcurrent framework: Qt provides a QtConcurrent framework for simplifying the programming of parallel processing and multithreaded tasks. Methods can be used
QtConcurrent::run()
to execute functions or lambda expressions in a new thread. You can also useQFuture
the andQFutureWatcher
classes to manage and listen to the results of asynchronous tasks. - Events and event queues: You can use Qt's event mechanism to send custom events from one thread to another. By customizing the event class and rewriting
event()
the method of the receiver object, the event delivery and custom processing between threads can be realized. - Shared data and locks: Through Qt's shared data and lock mechanism, data sharing and protection between threads can be realized. For example, you can use
QMutex
the andQMutexLocker
class to implement a mutex to prevent multiple threads from accessing a shared resource at the same time.
According to actual needs and complexity, you can choose a suitable inter-thread communication mechanism.
For simple communication, the signal-slot mechanism is usually the most common approach .
For more complex cases, other mechanisms can be chosen to meet the needs.
Note When using any inter-thread communication mechanism, pay attention to thread safety and data consistency.
Remark:
Signals and slots:
(1) Can span threads
(2) can transmit signal
(3) Can carry any object data when transmitting the signal
1.2 The solution to the imbalance between the sending data thread and the receiving data thread
When there is an imbalance between the sending data thread and the receiving data thread, data loss or processing delays may result.
To solve this problem, you can consider the following methods:
-
Use buffer: add a queue buffer between the sending data thread and the receiving data thread to temporarily store the data to be sent or received. This avoids frequent sending of data by the sender or frequent processing of data by the receiver. Buffers can be implemented using containers such as
QQueue
orQList
and ensure synchronization between sender and receiver. The sender can add data to the buffer, and the receiver reads data from the buffer for processing. -
Adjust the sending frequency: If the rate of sending data is much higher than the rate of receiving data, consider reducing the sending frequency to avoid data overload. The sending frequency can be controlled by adding an appropriate delay between sending data or using a timer .
-
Use thread pool: If the sending data thread is too busy, consider using thread pool to handle sending tasks. By allocating data to be sent to idle threads in the thread pool, the workload can be balanced and the rate at which data is sent is controlled.
-
Data compression or filtering: If the amount of data is too large or the data processing speed cannot keep up, you can consider compressing or filtering the data to reduce the amount of data or improve processing efficiency. Compression algorithms can be used for data compression, or rules or filters can be used to filter data, and only the required data can be selected for transmission or processing.
-
Optimize data processing logic: Check the processing logic of the receiving data thread to ensure that they can efficiently process the received data. It may be necessary to optimize algorithms and avoid unnecessary calculations or IO operations to increase processing speed.
Through the above method, the imbalance problem between the sending data thread and the receiving data thread can be solved to ensure that the data can be transmitted and processed on time. The specific method choice depends on your application scenario and needs.
Chapter 2 Communication Between Objects : Signal and Slot Communication
In Qt, object communication can be achieved through the signal and slot mechanism .
The following are the general steps for object communication:
- Create worker and main threads.
- Define the signal in the worker thread.
- Define the slot function in the main thread.
- Connect the signal to the slot function.
- Emit a signal in the worker thread to trigger the execution of the slot function.
Here's a simple example showing how to communicate between two objects (two objects inside a thread):
// MyWorker.h
#ifndef MYWORKER_H
#define MYWORKER_H
#include <QObject>
class MyWorker : public QObject {
Q_OBJECT
public:
explicit MyWorker(QObject *parent = nullptr);
public slots:
void doWork();
signals:
void resultReady(int result);
};
#endif // MYWORKER_H
// MyWorker.cpp
#include "MyWorker.h"
MyWorker::MyWorker(QObject *parent) : QObject(parent) {}
void MyWorker::doWork() {
// 执行耗时操作
int result = 42;
// 在工作线程中发射信号,将结果发送到主线程
emit resultReady(result);
}
// MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
public slots:
void handleResult(int result);
private slots:
void startWorker();
private:
MyWorker *worker;
};
#endif // MAINWINDOW_H
// MainWindow.cpp
#include "MainWindow.h"
#include "MyWorker.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent),
worker(new MyWorker(this))
{
connect(worker, &MyWorker::resultReady, this, &MainWindow::handleResult);
connect(this, &MainWindow::startWorker, worker, &MyWorker::doWork);
// 开始工作线程
emit startWorker();
}
MainWindow::~MainWindow() {
delete worker;
}
void MainWindow::handleResult(int result) {
qDebug() << "Result:" << result;
}
void MainWindow::startWorker() {
// 开始工作线程
emit startWorker();
}
In the above example, MyWorker
it is a worker thread class, which inherits from QObject, and defines resultReady
signal and doWork
slot functions in it. doWork
After the function performs a time-consuming operation, emit
it emits resultReady
a signal through the keyword and sends the result to the main thread.
MainWindow
Is a class of the main thread, which inherits from QMainWindow. In the constructor, connect the signal to the slot function via connect
the function . In this way, the function will be triggered to execute after receiving the signal emitted by the worker thread .MyWorker
resultReady
MainWindow
handleResult
handleResult
In MainWindow
the constructor of , start the worker thread through emit
the keyword emit startWorker
signal. In this way, the function in the worker thread doWork
will be executed and resultReady
the signal will be emitted.
It should be noted that the signal and slot mechanism can cross thread boundaries and communicate between different threads.
By using appropriate signal and slot connections, data transfer and interactive operations between threads can be achieved.
In addition, you need to pay attention to the following points when communicating between threads:
- Object Lifecycle: Ensures that objects are valid for the duration of the connection and are properly managed and released when no longer needed.
- Thread Safety: Any shared data accessed in different threads needs to use appropriate synchronization methods to ensure thread safety.
- Qt event loop: If you are doing time-consuming operations in worker threads, you can use
QCoreApplication::processEvents()
this to ensure that the event loop continues to process other messages to keep your application responsive.
Chapter 3 Inter-Thread Communication: Transferring Data Between Threads
By default, two objects communicating through signal and slot communication are in the same thread.
QT also supports communication between different thread objects through signals and slots! ! !
In Qt, passing data between threads can be achieved through the signal and slot mechanism .
Here's a common way:
- Create a sender thread and a receiver thread .
- Define the signal in the sender thread , and add the data type to be passed in the signal parameter .
- Define the slot function in the receiver thread to receive the signal and process the data.
- Connect the signal to the slot function.
Here is a simple example showing how to pass data between threads:
// WorkerThread.h
#ifndef WORKERTHREAD_H
#define WORKERTHREAD_H
#include <QThread>
// 发送数据线程:先接收数据,然后发送数据ready通知
class WorkerThread : public QThread {
Q_OBJECT
signals:
// 定义带参数的信号,用于传递数据
void dataReady(QString data);
protected:
void run() override;
};
#endif // WORKERTHREAD_H
// WorkerThread.cpp
#include "WorkerThread.h"
void WorkerThread::run() {
// 模拟耗时操作
QThread::sleep(2);
// 发射信号,传递数据
emit dataReady("Hello from worker thread!");
}
// MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
// 在main线程中,通过主窗口对象的槽函数中接收数据
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
public slots:
// 定义槽函数,用于接收信号传递的数据
void handleData(QString data);
private:
WorkerThread *workerThread;
};
#endif // MAINWINDOW_H
// MainWindow.cpp
#include "MainWindow.h"
#include "WorkerThread.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent),
workerThread(new WorkerThread())
{
// 将信号连接到槽函数
// 发送信号的数据格式与槽函数接收数据,具有相同的代表数据的参数!!!
connect(workerThread, &WorkerThread::dataReady, this, &MainWindow::handleData);
// 启动工作线程:接收数据,并把接收到的数据交给主线程的mainwindows对象的槽函数处理
workerThread->start();
}
MainWindow::~MainWindow() {
delete workerThread;
}
void MainWindow::handleData(QString data) {
// 处理接收到的数据
qDebug() << "Received data:" << data;
}
In the above example, WorkerThread
is a worker class that inherits from QThread
. WorkerThread
Signals are defined in , dataReady
which are used to pass data. In run
the method, the time-consuming operation is simulated, and the signal emit
is emitted through the keyword dataReady
, which carries a QString
type of data.
MainWindow
It is a class of the main thread. In the constructor, the signal WorkerThread
of the object is connected to the slot function in order to receive the data passed by the signal. Then, start the worker thread by calling the method .dataReady
handleData
workerThread
start
When a worker thread finishes performing a time-consuming operation and emits dataReady
a signal, the signal triggers a slot function MainWindow
in the class handleData
. In the slot function, you can process the received data and perform corresponding operations.
It should be noted that when transferring data between threads, the legality and thread safety of the data need to be guaranteed . At the same time, since Qt's signal and slot mechanism is based on the event loop, when using threads for data transfer, it may be necessary to handle the event loop in order to respond in time and handle the signal slot connection.