Qt Signal Slot Thread Safety
Author: Cao Qun
Original text: https://mp.weixin.qq.com/s/Mp…
Welcome to the official account of the technical team of the school network.
QT is a cross platform C + + GUI application development framework developed by QT company in 1991. It can be used to develop GUI programs as well as non GUI programs, such as console tools and servers. QT is an object-oriented framework. With special code generation extensions (called meta object compiler) and some macros, QT is easy to extend and allows real component programming. QT is a cross platform development framework, supporting windows, Linux, MacOS and other different platforms; QT has a large number of development documents and rich API, which brings great convenience to developers; QT users are more and more, and many excellent products are developed based on QT, such as WPS offic, opera browser, QT creator, etc. The core mechanism of QT is the signal and slot. Next, we analyze the implementation principle through the source code.
- signalWhen an object changes its state, the signal is emitted by the object, and the object is only responsible for sending the signal, and it does not know who is receiving the signal on the other end.
- groove: used to receive signals, and slots are just ordinary object member functions. A slot does not know if there is any signal connected to it.
- Signal to slot connection: all classes derived from QObject or its subclasses, such as QWidget, can contain signals and slots. It is managed by static method: QObject:: connect (sender, signal (signal), receiver, slot (slot)); where sender and receiver are pointers to objects, and signal() and slot() are macros for converting signals and slots.
The Qt signals/slots and property system are based on the ability to introspect the objects at runtime. Introspection means being able to list the methods and properties of an object and have all kinds of information about them such as the type of their arguments. QtScript and QML would have hardly been possible without that ability. The Qt signals/slots and property system are based on the ability to introspect the objects at runtime. Introspection means being able to list the methods and properties of an object and have all kinds of information about them such as the type of their arguments. QtScript and QML would have hardly been possible without that ability. QObjects are one of the fundamental building blocks of Qt applications. QObjects provide memory management, advanced event handling, and signals and slots: a devious mechanism to allow communication between QObjects and modules in a thread-safe manner, while allowing your system to remain loosely coupled and flexible. Qt provides thread support in the form of platform-independent threading classes, a thread-safe way of posting events, and signal-slot connections across threads. This makes it easy to develop portable multithreaded Qt applications and take advantage of multiprocessor machines. Home Articles Programming C/C. On the other hand, we might have to use synchronisation primitives like mutexes or wait conditions to model the flow of data in a realistic producer/consumer scenarios (like when Qt uses QMetaCallEvent for signal/slot connections crossing threads). This will shadow the impact the locks in the allocator has.
- 1. First of all, we set up a good environment, such as installing qt5.7 (including source code) + vs2013 and corresponding plug-ins on Windows system. We mainly compile and debug through vs.
- 2. We write a simple instance, build it, and copy the PDB of qtcore in the QT installation directory to our executable file directory, as shown in the following figure:
Here is the demo code we want to analyze:
// MainWindow.h
// MainWindow.cpp
We can create a QT project named demo, write the above code and build it. Under vs, we can import the QT project into a vs project, compile and generate it. The running results are as follows:
Click the middle button to see the console print the following information:
Step 1: basic structure:
When we analyze the code, we can see that in the header files test and MainWindow classes, there are Q_ For macro like object, we can see an additional MOC under the executable folder above_ MainWindow.cpp Of course, what we can’t do after we try to build the macro and the signal slot after we try to build the macro and the signal? Let’s take a look at this macro:
It turns out that this macro is some static and virtual methods. But if we add it to a class and do not implement it, it will definitely report an error. Why can it run normally? It turns out that QT helps us to do a lot of things. Before the compiler compiles the QT code, QT first translates the syntax of QT’s own extension. This operation is accomplished through MOC (meta object compiler), also known as “meta object compiler”. First, the MOC will analyze the source code, including Q_ The header file of object is generated as a C + + source file. The name of this file will be the source file name followed by MOC_ After that, it is processed by the compiler together with the original file. Then we think that the CPP at the beginning of MOC must implement the methods in the macro above and the assignment of data. Next, let’s look at the MOC_ MainWindow.cpp This document:
As we can see from the code above, it’s for Q_ The static data in object are assigned values, and those methods are implemented. These are generated by QT’s MOC compiler for us. The code is analyzed, and symbols are generated for signals and slots, as well as specific data structures. The following mainly records the reference count, size and offset of classes, signals and slots, which will be used later.
Through QT_ MOC_ After the macro literal is replaced, the following data is obtained:
Let’s take a look at QT below_ meta_ data_ MainWindow array structure: content has two columns. The first column is the total number, and the second column is the index describing the beginning of the array, such as 1, 14, / / methods, indicating that there is a method. We can see that slots start from index 14.
From the top source code, we can see that signal and slot are used to correlate signals and slots. What are the functions of these two macros? Let’s analyze:
analysis:
From the above, we can see that these two are actually string concatenation macros, which will splice “2” in front of the signal, such as “2clean()”, and splice “1” in front of slots, such as “1onclean()”. Among them, qflaglocation mainly stores method in const char * locations [count] in flageddebugsignatures in qthreaddata; Table is used to locate the row information corresponding to the code.
After precompiling, it is as follows:
Through the introduction of some basic macros and data structures above, we know that QT has done a lot of work for us, helped us generate MOC code, provided us with some macros, so that we can develop succinctly and conveniently. Then, how does QT associate signals with slots, that is, two different examples, and how to communicate through the signaling slot mechanism? Next, let’s look at the implementation principle of signal and slot correlation
The second step is the correlation between signal and slot
- 1. Check the string of signal and slot first, qsignal_ Code is 1; signal_ Code is 2.
- 2. Get metadata (the same for sender and receiver).
This method is our upper MOC_ MainWindow.cpp Medium.
According to debugging, we can see QObject:: D_ PTR > metaobject is empty, so smeta is the static metaobject variable above.
//First of all, we have to understand the definition of qmetaobject and qmetaobjectprivate
In QT, in order to achieve binary compatibility, a private class is generally defined. Qmetaobjectprivate is the private class of qmetaobject. Qmetaobject is responsible for some interface implementation, and qmetaobjectprivate is specifically implemented. These two classes are generally accessed by P pointer and D pointer. There is a macro:
Let’s see that the static metaobject above is a variable of type qmetaobject, where qmetaobject is assigned a value:
- 1) & QWidget:: staticmetaobject – > Superdata
- 2)qt_meta_stringdata_Test.data -> stringdata
- 3)qt_meta_stringdata_Test() -> data
- 4)qt_ static_ Metacall (callback function) – > static_ metacall
Among them, qmetaobject is the external structure, and the connection method inside calls or implements the connect in qmetaobjectprivate. The D member in qmetaobject is filled with the static metaobject data above, while the member in qmetaobjectprivate is filled with QT_ meta_ stringdata_ For the data in the test array, we can see that the first 14 data are filled. This is also the reason why MOC takes 14 as the cardinal number when generating methoddata. The conversion method is as follows:
- 3. Get and save the signal parameters and names. As follows, save the signal parameters and return the method name.
- 4. Calculate indexes (including base classes).
The implementation is as follows:
Where int handle = priv (M > D.Data) – > methoddata + 5i. We can analyze that, in fact, it is 14 + 5i. So why five? Because:
// signals: name, argc, parameters, tag, flags
1, 0, 24, 2, 0x06 / Public /,
// slots: name, argc, parameters, tag, flags
3, 0, 25, 2, 0x08 / Private /,
We can see that each signal or slot has five plastic representations.
- 5. Check the mask.
//Methodflags is an enumeration type. We can see that methodsignal = 0x04 and methodslot = 0x08;
// slots: name, argc, parameters, tag, flags
3, 0, 25, 2, 0x08 / Private /,
- 6. Judge the link type. The default is QT:: autoconnection.
We introduce some connection types:
Qt Signal Thread
- 1. Autoconnection: automatic connection: by default, the thread and bad object sent by the signal are equivalent to directconnection in one thread, and queuedconnection in different threads.
- 2. Directconnection: direct connection: it is equivalent to calling the slot function directly. However, when the signaled thread and the slot object are no longer the same thread, the slot function is executed in the issued signal.
- 3. Queuedconnection: queue connection: implemented internally through postevent. It is not called in real time, and the slot function is always executed in the thread where the slot function object is located. If the signal parameter is a reference type, a separate copy is made. Thread safe.
- 4. Blockingqueuedconnection: blocking connection: this connection method can only be used for the signaled thread and the object of the slot function. It can be used in a thread any more. It is implemented by semaphore + postevent, and is not called in real time. The slot function is always in the slot The function object is executed in the thread where the function object is located. However, the current thread will be blocked after the execution of the slot function is completed.
- 5. Uniqueconnection: prevents duplicate connections. If the current signal and slot are already connected, they are no longer connected.
Finally, it’s where the signal and slot are related to the core:
First, we need to understand the following data structures:
The above three data structures are very important. QObject is our most familiar base class, and qobjectprivate is its private class for specific implementation. Qobjectprivate inherits from qobjectdata and is accessed by P pointer and D pointer in the form of composition in QObject. In the process of signal and slot correlation, the data structure connection is a very important data structure. The following structure is a vector of the connectionlist:
With the above data structure, we can analyze the following link process. We can see that the following is the connection of the called qmetaobjectprivate, and then the pointer wrapping with qmetaobject:: Connection:
QObjectPrivate:: get (s) method is actually getting a QObjectPrivate instance in QObjec, then calling addConnection method to add to the linked list:
The structure is as follows:
analysis:
- 1. Each QObject object has a QObject connectionlistvector structure, which is a vector container. The basic units in it are data of the connectionlist type. The number of connectionlists is the same as the number of signals of the QObject object. Each connectionlist corresponds to a signal, which records all connections connected to the signal. We have seen that there are two important members in the definition of connectionlist: first and last. They are both pointers of connection type, pointing to the first and last connection connected to this signal respectively. All connections connected to this signal are organized in a one-way linked list. The nextconnectionlist member in the connection structure is used to point to the next connection in the list.
- 2. At the same time, each QObject object also has a senders member. Senders is a pointer of connection type. Senders itself is the head node of a linked list. All nodes in the list are connected to a slot on the QObject object. However, the list mentioned in the following paragraph is not the same, although they may have some common nodes.
- 3. Each connection object is in two linked lists at the same time. One is a one-way linked list organized by nextconnectionlist members of connection. The common point of each node in this single list is that they all rely on the same signal of the same QObject object. The head node of this list is the first in the connectionlist structure corresponding to the signal; the other is organized by the next and prev members of connection Bidirectional linked list. The common feature of each node in this bi-directional linked list is that their slots are on the same QObject object, and the head node of the list is the sender of the QObject object. The two linked lists will have cross (common nodes), but they have different link pointers, so they are not the same list.
- 4. In connect, a new connection object is first created. After setting the connection information, it is added to the two linked lists mentioned above. When disconnecting, it is removed from the two linked lists and then deleted. When a QObject object is destroyed, all connections in the bidirectional linked list pointed to by its sender pointer will be removed one by one!
Step 3: send signal to receive signal
- 1, we click on the button above and then call it into the onDestory slot, which is where we write the signal trigger:
- 2. The next step is the MOC_ MainWindow.cpp The code inside calls the static method activate of qmetaobject
//Then go to the real qmetaobject:: activate
Our example is autocontion mode, so the following code will be executed for callback:
Qt Signal Slot Parameter
We finally see that the function calls back to the MOC_ MainWindow.cpp Inside, then call the corresponding slot onClean;
Finally, after calling here, print out: “MainWindow:: onclean”
Finally, after the call is finished, it will return to ondestory
Note: if we do the M_ Release operation of testwidget object (delete M_ Testwidget), and then to emit clean() in ondestory(); after accessing members, you must crash, so pay attention.
1、https://woboq.com/blog/how-qt…
2. Qt5.7 source code
Qt Signal Slot Thread Safety Pins
3. The signal and slot demo implemented in C + + http://note.youdao.com/notesh…