QObject-Internals: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
No edit summary
(Marked as outdated)
 
(3 intermediate revisions by 3 users not shown)
Line 1: Line 1:
[[Category:Developing_Qt::Qt_Internals]]
{{Outdated|reason=Qt 4}}
 
= QObject Internals =
 
== How Signals and Slots Works. ==
== How Signals and Slots Works. ==


Line 9: Line 6:
== moc ==
== moc ==


The moc is there to generate the QMetaObject contents.<br />It parses the headers and generate source code that contains the metaobject and the code of the signals.
The moc is there to generate the QMetaObject contents.
It parses the headers and generate source code that contains the metaobject and the code of the signals.


=== Cloned Method ===
=== Cloned Method ===
Line 15: Line 13:
If you have a signal or a slot with default arguments, the signature are duplicated as if there was overload with and without those argument argument.
If you have a signal or a slot with default arguments, the signature are duplicated as if there was overload with and without those argument argument.


First is the &quot;original&amp;quot; one, with the full number of argument.<br />Then follow all the clones: they have the flag MethodFlags::MethodCloned in the QMetaObject method flags
First is the "original" one, with the full number of argument.
Then follow all the clones: they have the flag MethodFlags::MethodCloned in the QMetaObject method flags


== methodIndex and signalIndex ==
== methodIndex and signalIndex ==


In each QMetaObject, the slots, signals, and other invokable methods of that object<br />have an index starting from 0. They are ordered such that the signals comes first, then the slot, then the other method.
In each QMetaObject, the slots, signals, and other invokable methods of that object
have an index starting from 0. They are ordered such that the signals comes first, then the slot, then the other method.


This index is called the relativeIndex in the code, and can be obtained by QMetaObjectPrivate::indexOf{Signal,Slot}Relative. This function returns the index, but also via its baseObject argument, the QMetaObject in which that slot belogs.
This index is called the relativeIndex in the code, and can be obtained by QMetaObjectPrivate::indexOf{Signal,Slot}Relative. This function returns the index, but also via its baseObject argument, the QMetaObject in which that slot belogs.
Line 25: Line 25:
The IndexOfMethod call of the QObject::qt_static_metacall function also returns that relativeIndex
The IndexOfMethod call of the QObject::qt_static_metacall function also returns that relativeIndex


Then there is the method index: it is the index returned by the public API QMetaObject::indexOf{Signal,Slot,Method}<br />That is basically the relativeIndex + QMetaObject::methodOffset()<br />This is the only index avaliable from the public API
Then there is the method index: it is the index returned by the public API QMetaObject::indexOf{Signal,Slot,Method}
That is basically the relativeIndex + QMetaObject::methodOffset()
This is the only index avaliable from the public API


The signalIndex is used from Qt 4.6 in the connectionLists. It was introduced because the connectionList only care about signals, and not the slots, and that there might be a lot of slots wasting space in that vector. It is only used internaly, and not avaliable through the public API.<br />The main difference is that it does not contains the slots. So the signalIndex is usually less than the methodIndex for a given signal (and it only exist for signal)<br />The second difference is that for cloned signal, we use the original instead. (Hence the call to QMetaObjectPrivate::originalClone)
The signalIndex is used from Qt 4.6 in the connectionLists. It was introduced because the connectionList only care about signals, and not the slots, and that there might be a lot of slots wasting space in that vector. It is only used internaly, and not avaliable through the public API.
The main difference is that it does not contains the slots. So the signalIndex is usually less than the methodIndex for a given signal (and it only exist for signal)
The second difference is that for cloned signal, we use the original instead. (Hence the call to QMetaObjectPrivate::originalClone)


== connectionLists Data Structure ==
== connectionLists Data Structure ==


connectionLists is a vector of lists of connections.<br />The index is the signalIndex, and lists are single linked list of connections represented with QObjectPrivate::Connection.
connectionLists is a vector of lists of connections.
The index is the signalIndex, and lists are single linked list of connections represented with QObjectPrivate::Connection.


The vector contains a pointer to the first Connection for that signal, and because we want the connection to be O (1), we store also the last connection. This last connection also helps to stop before the connection that would have been added after the signal has been emitted while emitting that signal. The linked list works by following the QObjectPrivate::Connection::nextConnectionList.
The vector contains a pointer to the first Connection for that signal, and because we want the connection to be O (1), we store also the last connection. This last connection also helps to stop before the connection that would have been added after the signal has been emitted while emitting that signal. The linked list works by following the QObjectPrivate::Connection::nextConnectionList.
Line 37: Line 42:
The Connection's are part of another linked list: the object sender's list. This list is used to be able to remove the connections when the object is destroyed. The starts of the list is QObjectPrivate::senders. And it is a (semi-) double linked list. We can get to the next element of that list using QObjectPrivate::Connection::next. But QObjectPrivate::Connection::prev is a pointer to the Connection::next of the previous element, or the the QObjectPrivate::senders if it is the first. It is like that because we only need to iterate that list one way, but we need to quickly O (1) remove connection from that list while we disconnect (or if the sender get detroyed)
The Connection's are part of another linked list: the object sender's list. This list is used to be able to remove the connections when the object is destroyed. The starts of the list is QObjectPrivate::senders. And it is a (semi-) double linked list. We can get to the next element of that list using QObjectPrivate::Connection::next. But QObjectPrivate::Connection::prev is a pointer to the Connection::next of the previous element, or the the QObjectPrivate::senders if it is the first. It is like that because we only need to iterate that list one way, but we need to quickly O (1) remove connection from that list while we disconnect (or if the sender get detroyed)


When an Object is destroyed:<br />* That QObjectPrivate::senders list will be iterated when the object is destroyed, and all the Connection::receiver will be set to 0, also Connection::receiver-&gt;connectionLists-&gt;dirty will be set to true. That way removing a connection is O (1) and destroying an object is O (n), n is the number of slot of this object connected to a signal (possibly in another object)<br />* each of the QObjectPrivate::connectionLists are also iterated to remove the Connection in the senders lists.
When an Object is destroyed:
* That QObjectPrivate::senders list will be iterated when the object is destroyed, and all the Connection::receiver will be set to 0, also Connection::receiver->connectionLists->dirty will be set to true. That way removing a connection is O (1) and destroying an object is O (n), n is the number of slot of this object connected to a signal (possibly in another object)
* each of the QObjectPrivate::connectionLists are also iterated to remove the Connection in the senders lists.


The lists are protected by the signalSlotMutex(QObject *)<br />The connectionLists by the mutex of the sender, and the senders by the mutex of the receiver.<br />So to modify a Connection, you need to lock the two mutex, but if you only access them, locking one mutex is enough.
The lists are protected by the signalSlotMutex(QObject *)
The connectionLists by the mutex of the sender, and the senders by the mutex of the receiver.
So to modify a Connection, you need to lock the two mutex, but if you only access them, locking one mutex is enough.


=== History ===
=== History ===


That data structure has changed a lot in Qt4 history<br />In Qt 4.0 it was a global, mutex protected, big list of connection, indexed with a QHash.
That data structure has changed a lot in Qt4 history
In Qt 4.0 it was a global, mutex protected, big list of connection, indexed with a QHash.


In Qt 4.4 it was changed to a QVector&amp;lt;QList&amp;lt;QObjectPrivate::Connection&amp;gt;&gt; connectionLists and QList&amp;lt;QObjectPRivate::Sender&amp;gt; senders in order to optimize QMetaObject;;activate
In Qt 4.4 it was changed to a QVector<QList<QObjectPrivate::Connection>> connectionLists and QList<QObjectPRivate::Sender> senders in order to optimize QMetaObject;;activate

Latest revision as of 18:08, 24 March 2016

IMPORTANT: The content of this page is outdated. Reason: Qt 4
If you have checked or updated this page and found the content to be suitable, please remove this notice.

How Signals and Slots Works.

See http://woboq.com/blog/how-qt-signals-slots-work.html

moc

The moc is there to generate the QMetaObject contents. It parses the headers and generate source code that contains the metaobject and the code of the signals.

Cloned Method

If you have a signal or a slot with default arguments, the signature are duplicated as if there was overload with and without those argument argument.

First is the "original" one, with the full number of argument. Then follow all the clones: they have the flag MethodFlags::MethodCloned in the QMetaObject method flags

methodIndex and signalIndex

In each QMetaObject, the slots, signals, and other invokable methods of that object have an index starting from 0. They are ordered such that the signals comes first, then the slot, then the other method.

This index is called the relativeIndex in the code, and can be obtained by QMetaObjectPrivate::indexOf{Signal,Slot}Relative. This function returns the index, but also via its baseObject argument, the QMetaObject in which that slot belogs.

The IndexOfMethod call of the QObject::qt_static_metacall function also returns that relativeIndex

Then there is the method index: it is the index returned by the public API QMetaObject::indexOf{Signal,Slot,Method} That is basically the relativeIndex + QMetaObject::methodOffset() This is the only index avaliable from the public API

The signalIndex is used from Qt 4.6 in the connectionLists. It was introduced because the connectionList only care about signals, and not the slots, and that there might be a lot of slots wasting space in that vector. It is only used internaly, and not avaliable through the public API. The main difference is that it does not contains the slots. So the signalIndex is usually less than the methodIndex for a given signal (and it only exist for signal) The second difference is that for cloned signal, we use the original instead. (Hence the call to QMetaObjectPrivate::originalClone)

connectionLists Data Structure

connectionLists is a vector of lists of connections. The index is the signalIndex, and lists are single linked list of connections represented with QObjectPrivate::Connection.

The vector contains a pointer to the first Connection for that signal, and because we want the connection to be O (1), we store also the last connection. This last connection also helps to stop before the connection that would have been added after the signal has been emitted while emitting that signal. The linked list works by following the QObjectPrivate::Connection::nextConnectionList.

The Connection's are part of another linked list: the object sender's list. This list is used to be able to remove the connections when the object is destroyed. The starts of the list is QObjectPrivate::senders. And it is a (semi-) double linked list. We can get to the next element of that list using QObjectPrivate::Connection::next. But QObjectPrivate::Connection::prev is a pointer to the Connection::next of the previous element, or the the QObjectPrivate::senders if it is the first. It is like that because we only need to iterate that list one way, but we need to quickly O (1) remove connection from that list while we disconnect (or if the sender get detroyed)

When an Object is destroyed:

  • That QObjectPrivate::senders list will be iterated when the object is destroyed, and all the Connection::receiver will be set to 0, also Connection::receiver->connectionLists->dirty will be set to true. That way removing a connection is O (1) and destroying an object is O (n), n is the number of slot of this object connected to a signal (possibly in another object)
  • each of the QObjectPrivate::connectionLists are also iterated to remove the Connection in the senders lists.

The lists are protected by the signalSlotMutex(QObject *) The connectionLists by the mutex of the sender, and the senders by the mutex of the receiver. So to modify a Connection, you need to lock the two mutex, but if you only access them, locking one mutex is enough.

History

That data structure has changed a lot in Qt4 history In Qt 4.0 it was a global, mutex protected, big list of connection, indexed with a QHash.

In Qt 4.4 it was changed to a QVector<QList<QObjectPrivate::Connection>> connectionLists and QList<QObjectPRivate::Sender> senders in order to optimize QMetaObject;;activate