Qt Cross Thread Signal Slot
2021年2月16日Register here: http://gg.gg/obmrq
Cross-thread signal slot, how to send char. c,multithreading,qt,signals-slots. The problem you have is completely unrelated to Qt, signals or multiple threads. The char. you’re creating isn’t null-terminated, so you cannot use it with functions (or operators) that expect char.s to be C strings - they rely on the null terminator. Signals & Slots, Signals and slots are made possible by Qt’s meta-object system. To one signal, the slots will be executed one after the other, in the order they have valueChanged, and it has a slot which other objects can send signals to. The context object provides information about in which thread the receiver should be executed.
*Qt Signal Slot Thread
*Qt Signal Slot Not Working
*Qt Signal Slot
*Qt Signals And Slots Tutorial
I’m using a Qt cross-thread (QueuedConnection) signal and slot to communicate between my service thread and the main thread. The problem I am having is that although the service thread emits the signal (well it executes the instruction) the slot in the main thread doesn’t get called. I’ve removed all of the TCP server code to simplify things. I am developing a cross-platform system (Windows and Ubuntu) that needs signal and slot communication between two QObjects living in different threads. When both QObjects live in the same thread, the performance difference between Windows and Ubuntu is negligible, but when I move one the QObjects to another thread I notice the performance on.The article is almost done, but it needs a bit of polishing and some good examples. Any review or contribution is welcome! Discussion about this article happens in this thread.
EnArBgDeElEsFaFiFrHiHuItJaKnKoMsNlPlPtRuSqThTrUkZh
*1Introduction
*2Events and the event loop
*3Qt thread classes
*4Threads and QObjects
*5When should I use threads?
*6When shouldn’t I use threads?
You’re doing it wrong. — Bradley T. Hughes
One of the most popular topics on the ’#qt IRC channel’:irc://irc.freenode.net/#qt is threading: many people join the channel and ask how they should solve their problem with some code running in a different thread.
Nine times out of ten, a quick inspection of their code shows that the biggest problem is the very fact they’re using threads in the first place, and they’re falling in one of the endless pitfalls of parallel programming.
The ease of creating and running threads in Qt, combined with some lack of knowledge about programming styles (especially asynchronous network programming, combined with Qt’s signals and slots architecture) and/or habits developed when using other tookits or languages, usually leads to people shooting themselves in the foot. Moreover, threading support in Qt is a double-edged sword: while it makes it very simple for you to do multithread programming, it adds a certain number of features (especially when it comes to interaction with QObjects) you must be aware of.
The purpose of this document is not to teach you how to use threads, do proper locking, exploit parallelism, nor write scalable programs; there are many good books about these topics; for instance, take a look to the recommended reading list on this page. Instead, this small article is meant to be a guide to introduce users to threading in Qt 4, in order to avoid the most common pitfalls and help them to develop code that is at the same time more robust and with a better structure.Prerequisites
Think of it this way: threads are like salt, not like pasta.
You like salt, I like salt, we all like salt. But we eat more pasta.— Larry McVoy
Not being a general-purpose introduction to (threads) programming, we expect you to have some previous knowledge about:
*C++ basics (though most suggestions do apply to other languages as well);
*Qt basics: QObjects, signals and slots, event handling;
*what a thread is and what the relationships are between threads, processes and the operating system;
*how to start and stop a thread, and wait for it to finish, under (at least) one major operating system;
*how to use mutexes, semaphores and wait conditions to create thread-safe/reentrant functions, data structures, classes.
In this document we’ll follow the Qt naming conventions, which are:
*Reentrant A class is reentrant if it’s safe to use its instances from more than one thread, provided that at most one thread is accessing the same instance at the same time. A function is reentrant if it’s safe to invoke it from more than one thread at the same, provided that each invocation references unique data. In other words, this means that users of that class/function must serialize all accesses to instances/shared data by means of some external locking mechanism.
*Thread-safe A class is thread-safe if it’s safe to use its instances from more than one thread at the same time. A function is thread-safe if it’s safe to invoke it from more than one thread at the same time even if the invocations reference shared data.
Being an event-driven toolkit, events and event delivery play a central role in Qt architecture. In this article we’ll not give a comprehensive coverage about this topic; we’ll instead focus on some thread-related key concepts (see here and here for more information about the Qt event system).
An event in Qt is an object which represents something interesting that happened; the main difference between an event and a signal is that events are targeted to a specific object in our application (which decides what to do with that event), while signals are emitted ’in the wild’. From a code point of view, all events are instances of some subclass of QEvent, and all QObject-derived classes can override the QObject::event() virtual method in order to handle events targeted to their instances.
Events can be generated from both inside and outside the application; for instance:
*QKeyEvent and QMouseEvent objects represent some kind of keyboard and mouse interaction, and they come from the window manager;
*QTimerEvent objects are sent to a QObject when one of its timers fires, and they (usually) come from the operating system;
*QChildEvent objects are sent to a QObject when a child is added or removed, and they come from inside your Qt application.
The important thing about events is that they’re not delivered as soon as they’re generated; they’re instead queued up in an event queue and sent sometime later. The dispatcher itself loops around the event queue and sends queued events to their target objects, and therefore it is called the event loop. Conceptually, this is how an event loop looks (see the Qt Quarterly article linked above):while (is_active){
wait_for_more_events();}
We enter Qt’s main event loop by running QCoreApplication::exec(); this call blocks until QCoreApplication::exit() or QCoreApplication::quit() are called, terminating the loop.
The ’wait_for_more_events()’ function blocks (that is, it’s not a busy wait) until some event is generated. If we think about it, all that can generate events at that point is some external source (dispatching for all internal events is now complete and there were no more pending events in the event queue to delivery). Therefore, the event loop can be woken up by:
*window manager activity (key/mouse presses, interaction with the windows, etc.);
*sockets activity (there’s some data available to read, or a socket is writable without blocking, there’s a new incoming connection, etc.);
*timers (i.e. a timer fired);
*events posted from other threads (see later).
In a UNIX-like system, window manager activity (i.e. X11) is notified to applications via sockets (Unix Domain or TCP/IP), since clients use them to communicate with the X server. If we decide to implement cross-thread event posting with an internal socketpair(2), all that is left is being woken up by activity on:
*sockets;
*timers;
which is exactly what the select(2) system call does: it watches over a set of descriptors for activity and it times out (with a configurable timeout) if there’s no activity for a certain while. All Qt needs to do is converting what select returns into an object of the right QEvent subclass and queue it up in the event queue. Now you know what’s inside an event loop :)What requires a running event loop?
This isn’t an exhaustive list, but if you have the overall picture, you should be able to guess which classes require a running event loop.
*Widgets painting and interaction: QWidget::paintEvent() will be called when delivering QPaintEvent objects, which are generated both by calling QWidget::update() (i.e. internally) or by the window manager (for instance, because a hidden window was shown). The same thing holds for all kinds of interaction (keyboard, mouse, etc.): the corresponding events will require an event loop to be dispatched.
*Timers: long story short, they’re fired when select(2) or similar calls time out, therefore you need to let Qt do those calls for you by returning to the event loop.
*Networking: all low-level Qt networking classes (QTcpSocket, QUdpSocket, QTcpServer, etc.) are asynchronous by design. When you call read(), they just return already available data; when you call write(), they schedule the writing for later. It’s only when you return to the event loop the actual reading/writing takes place. Notice that they do offer synchronous methods (the waitFor* family of methods), but their use is discouraged because they block the event loop while waiting. High-level classes, like QNetworkAccessManager, simply do not offer any synchronous API and require an event loop.Blocking the event loop
Before discussing why you should never ever block the event loop, let’s try to figure out what this ’blocking’ means. Suppose you have a Button widget which emits a signal when clicked; connected to this signal there’s a slot of our Worker object, which does a lot of work. After you click the button, the stack trace will look like this (the stack grows downwards):
*main(int, char )
*QApplication::exec()
*[…]
*QWidget::event(QEvent )
*Button::mousePressEvent(QMouseEvent)
*Button::clicked()
*[…]
*Worker::doWork()
In main() we started the event loop, as usual, by calling QApplication::exec() (line 2). The window manager sent us the mouse click, which was picked up by the Qt kernel, converted in a QMouseEvent and sent to our widget’s event() method (line 4) by QApplication::notify() (not shown here). Since Button didn’t override event(), the base class implementation (QWidget) is called. QWidget::event() detects the event is actually a mouse click and calls the specialized event handler, that is, Button::mousePressEvent() (line 5). We overrode this method to emit the Button::clicked() signal (line 6), which invokes the Worker::doWork slot of our worker object (line 7).
While the worker is busy working, what’s the event loop doing? You should’ve guessed it: nothing! It dispatched the mouse press event and it’s blocked waiting for the event handler to return. We managed to block the event loop, which means that no event is sent any more, until we return from the doWork() slot, up the stack, to the event loop, and let it process pending events.
With the event delivery stuck, widgets won’t update themselves (QPaintEvent objects will sit in the queue), no further interaction with widgets is possible (for the same reason), timers won’t fire and networking communications will slow down and stop. Moreover, many window managers will detect that your application is not handling events any more and tell the user that your application isn’t responding. That’s why is so important to quickly react to events and return to the event loop as soon as possible!Forcing event dispatching
So, what do we do if we have a long task to run and don’t want to block the event loop? One possible answer is to move the task into another thread: in the next sections we’ll see how to do that. We also have the option to manually force the event loop to run, by (repeatedly) calling QCoreApplication::processEvents() inside our blocking task. QCoreApplication::processEvents() will process all the events in the event queue and return to the caller.
Another available option we can use to forcibly reenter the event loop is the QEventLoop class. By calling QEventLoop::exec() we reenter the event loop, and we can connect signals to the QEventLoop::quit() slot to make it quit. For instance:
QNetworkAccessManager qnam;QNetworkReply *reply = qnam.get(QNetworkRequest(QUrl(…)));QEventLoop loop;QObject::connect(reply, SIGNAL (finished()), &loop, SLOT (quit()));loop.exec();/* reply has finished, use it */
QNetworkReply doesn’t offer a blocking API and requires an event loop to be running. We enter a local QEventLoop, and when the reply has finished, the local event loop quits.
Be very careful when reentering the event loop ’by other paths’: it can lead to unwanted recursions! Let’s go back to the Button example. If we call QCoreApplication::processEvents() inside the doWork() slot, and the user clicks again on the button, the doWork() slot will be invoked again:
*main(int, char)
*QApplication::exec()
*[…]
*QWidget::event(QEvent )
*Button::mousePressEvent(QMouseEvent)
*Button::clicked()
*[…]
*Worker::doWork() // first, inner invocation
*QCoreApplication::processEvents() // we manually dispatch events and…
*[…]
*QWidget::event(QEvent * ) // another mouse click is sent to the Button…
*Button::mousePressEvent(QMouseEvent *)
*Button::clicked() // which emits clicked() again…
*[…]
*Worker::doWork() // DANG! we’ve recursed into our slot.
A quick and easy workaround for this is passing QEventLoop::ExcludeUserInputEvents to QCoreApplication::processEvents(), which tells the event loop to not dispatch any user input event (the events will simply stay in the queue).
Luckily, the same thing does not apply to deletion events (the ones posted in the event queue by QObject::deleteLater()). In fact, they are handled in a special way by Qt, and are processed only if the running event loop has a smaller degree of ’nesting’ (w.r.t. event loops) than the one where deleteLater was called. For instance:
QObject *object = new QObject;object->deleteLater();QDialog dialog;dialog.exec();
will not make object a dangling pointer (the event loop entered by QDialog::exec() is more nested than the deleteLater call). The same thing applies to local event loops started with QEventLoop. The only notable exception I’ve found to this rule (as of Qt 4.7.3) is that if deleteLater is called when NO event loop is running, then the first event loop entered will pick up the event and delete the object. This is pretty much reasonable, since Qt does not know about any ’outer’ loop that will eventually perform the deletion, and therefore deletes the object immediately.
.
A computer is a state machine. Threads are for people who can’t program state machines.
— Alan Cox
Qt has had thread support for many years (Qt 2.2, released on 22 Sept 2000, introduced the QThread class.), and with the 4.0 release thread support is enabled by default on all supported platforms (although it can be turned off, see here for more details). Qt now offers several classes for dealing with threads; let’s start with an overview.QThread
QThread is the central, low-level class for thread support in Qt. A QThread object represents one thread of execution. Due to the cross-platform nature of Qt, QThread manages to hide all the platform-specific code that is needed to use threads on different operating systems.
In order to use a QThread to run some code in a thread, we can subclass it and override the QThread::run() method:
class Thread : public QThread {protected:
};
Then we can use
Thread *t = new Thread;t->start(); // start(), not run()!
to actually start the new thread. Note that since Qt 4.4 QThread is no longer an abstract class; now the virtual method QThread::run() instead simply calls QThread::exec();, which starts the thread’s event loop (more info on this later).
QRunnable and QThreadPool
QRunnable is a lightweight abstract class that can be used to start a task in another thread in a ’run and forget’ fashion. In order to do so, all we have to do is subclass QRunnable and implement its run() pure virtual method:
class Task : public QRunnable {public:
};
To actually run a QRunnable object we use the QThreadPool class, which manages a pool of threads. By calling QThreadPool::start(runnable) we put a QRunnable in a QThreadPool’s runqueue; as soon as a thread becomes available, the QRunnable will be picked up and run into that thread. All Qt applications have a global thread pool available by calling QThreadPool::globalInstance(), but one can always create a private QThreadPool instance and manage it explicitely.
Notice that, not being a QObject, QRunnable has no built-in means of explicitely communicating something to other components; you have to code that by hand, using low-level threading primitives (like a mutex-guarded queue for collecting results, etc.).QtConcurrent
QtConcurrent is a higher-level API, built on top of QThreadPool, useful to deal with the most common parallel computation patterns: map, reduce, and filter ; it also offers a QtConcurrent::run() method that can be used to easily run a function in another thread.
Unlike QThread and QRunnable, QtConcurrent does not require us to use low-level synchronization primitives: all QtConcurrent methods instead return a QFuture object, which can be used to query the computation status (its progress), to pause/resume/cancel the computation, and that also contains its results. The QFutureWatcher class can be used to monitor a QFuture progress and interact with it by means of signals and slots (notice that QFuture, being a value-based class, doesn’t inherit QObject).Feature comparisonQThreadQRunnableQtConcurrent[1]High level API✘✘✔Job-oriented✘✔✔Builtin support for pause/resume/cancel✘✘✔Can run at a different priority✔✘✘Can run an event loop✔✘✘Per-thread event loop
So far we’ve always talked about ’the event loop’, taking somehow per granted that there’s only one event loop in a Qt application. This is not the case: QThread objects can start thread-local event loops running in the threads they represent. Therefore, we say that the main event loop is the one created by the thread which invoked main(), and started with QCoreApplication::exec() (which must be called from that thread). This is also called the GUI thread, because it’s the only thread in which GUI-related operations are allowed. A QThread local event loop can be started instead by calling QThread::exec() (inside its run() method):
class Thread : public QThread {protected:
exec();
};
As we mentioned before, since Qt 4.4 QThread::run() is no longer a pure virtual method; instead, it calls QThread::exec(). Exactly like QCoreApplication, QThread has also the QThread::quit() and QThread::exit() methods to stop the event loop.
A thread event loop delivers events for all QObjects that are living in that thread; this includes, by default, all objects that ar
https://diarynote-jp.indered.space
Cross-thread signal slot, how to send char. c,multithreading,qt,signals-slots. The problem you have is completely unrelated to Qt, signals or multiple threads. The char. you’re creating isn’t null-terminated, so you cannot use it with functions (or operators) that expect char.s to be C strings - they rely on the null terminator. Signals & Slots, Signals and slots are made possible by Qt’s meta-object system. To one signal, the slots will be executed one after the other, in the order they have valueChanged, and it has a slot which other objects can send signals to. The context object provides information about in which thread the receiver should be executed.
*Qt Signal Slot Thread
*Qt Signal Slot Not Working
*Qt Signal Slot
*Qt Signals And Slots Tutorial
I’m using a Qt cross-thread (QueuedConnection) signal and slot to communicate between my service thread and the main thread. The problem I am having is that although the service thread emits the signal (well it executes the instruction) the slot in the main thread doesn’t get called. I’ve removed all of the TCP server code to simplify things. I am developing a cross-platform system (Windows and Ubuntu) that needs signal and slot communication between two QObjects living in different threads. When both QObjects live in the same thread, the performance difference between Windows and Ubuntu is negligible, but when I move one the QObjects to another thread I notice the performance on.The article is almost done, but it needs a bit of polishing and some good examples. Any review or contribution is welcome! Discussion about this article happens in this thread.
EnArBgDeElEsFaFiFrHiHuItJaKnKoMsNlPlPtRuSqThTrUkZh
*1Introduction
*2Events and the event loop
*3Qt thread classes
*4Threads and QObjects
*5When should I use threads?
*6When shouldn’t I use threads?
You’re doing it wrong. — Bradley T. Hughes
One of the most popular topics on the ’#qt IRC channel’:irc://irc.freenode.net/#qt is threading: many people join the channel and ask how they should solve their problem with some code running in a different thread.
Nine times out of ten, a quick inspection of their code shows that the biggest problem is the very fact they’re using threads in the first place, and they’re falling in one of the endless pitfalls of parallel programming.
The ease of creating and running threads in Qt, combined with some lack of knowledge about programming styles (especially asynchronous network programming, combined with Qt’s signals and slots architecture) and/or habits developed when using other tookits or languages, usually leads to people shooting themselves in the foot. Moreover, threading support in Qt is a double-edged sword: while it makes it very simple for you to do multithread programming, it adds a certain number of features (especially when it comes to interaction with QObjects) you must be aware of.
The purpose of this document is not to teach you how to use threads, do proper locking, exploit parallelism, nor write scalable programs; there are many good books about these topics; for instance, take a look to the recommended reading list on this page. Instead, this small article is meant to be a guide to introduce users to threading in Qt 4, in order to avoid the most common pitfalls and help them to develop code that is at the same time more robust and with a better structure.Prerequisites
Think of it this way: threads are like salt, not like pasta.
You like salt, I like salt, we all like salt. But we eat more pasta.— Larry McVoy
Not being a general-purpose introduction to (threads) programming, we expect you to have some previous knowledge about:
*C++ basics (though most suggestions do apply to other languages as well);
*Qt basics: QObjects, signals and slots, event handling;
*what a thread is and what the relationships are between threads, processes and the operating system;
*how to start and stop a thread, and wait for it to finish, under (at least) one major operating system;
*how to use mutexes, semaphores and wait conditions to create thread-safe/reentrant functions, data structures, classes.
In this document we’ll follow the Qt naming conventions, which are:
*Reentrant A class is reentrant if it’s safe to use its instances from more than one thread, provided that at most one thread is accessing the same instance at the same time. A function is reentrant if it’s safe to invoke it from more than one thread at the same, provided that each invocation references unique data. In other words, this means that users of that class/function must serialize all accesses to instances/shared data by means of some external locking mechanism.
*Thread-safe A class is thread-safe if it’s safe to use its instances from more than one thread at the same time. A function is thread-safe if it’s safe to invoke it from more than one thread at the same time even if the invocations reference shared data.
Being an event-driven toolkit, events and event delivery play a central role in Qt architecture. In this article we’ll not give a comprehensive coverage about this topic; we’ll instead focus on some thread-related key concepts (see here and here for more information about the Qt event system).
An event in Qt is an object which represents something interesting that happened; the main difference between an event and a signal is that events are targeted to a specific object in our application (which decides what to do with that event), while signals are emitted ’in the wild’. From a code point of view, all events are instances of some subclass of QEvent, and all QObject-derived classes can override the QObject::event() virtual method in order to handle events targeted to their instances.
Events can be generated from both inside and outside the application; for instance:
*QKeyEvent and QMouseEvent objects represent some kind of keyboard and mouse interaction, and they come from the window manager;
*QTimerEvent objects are sent to a QObject when one of its timers fires, and they (usually) come from the operating system;
*QChildEvent objects are sent to a QObject when a child is added or removed, and they come from inside your Qt application.
The important thing about events is that they’re not delivered as soon as they’re generated; they’re instead queued up in an event queue and sent sometime later. The dispatcher itself loops around the event queue and sends queued events to their target objects, and therefore it is called the event loop. Conceptually, this is how an event loop looks (see the Qt Quarterly article linked above):while (is_active){
wait_for_more_events();}
We enter Qt’s main event loop by running QCoreApplication::exec(); this call blocks until QCoreApplication::exit() or QCoreApplication::quit() are called, terminating the loop.
The ’wait_for_more_events()’ function blocks (that is, it’s not a busy wait) until some event is generated. If we think about it, all that can generate events at that point is some external source (dispatching for all internal events is now complete and there were no more pending events in the event queue to delivery). Therefore, the event loop can be woken up by:
*window manager activity (key/mouse presses, interaction with the windows, etc.);
*sockets activity (there’s some data available to read, or a socket is writable without blocking, there’s a new incoming connection, etc.);
*timers (i.e. a timer fired);
*events posted from other threads (see later).
In a UNIX-like system, window manager activity (i.e. X11) is notified to applications via sockets (Unix Domain or TCP/IP), since clients use them to communicate with the X server. If we decide to implement cross-thread event posting with an internal socketpair(2), all that is left is being woken up by activity on:
*sockets;
*timers;
which is exactly what the select(2) system call does: it watches over a set of descriptors for activity and it times out (with a configurable timeout) if there’s no activity for a certain while. All Qt needs to do is converting what select returns into an object of the right QEvent subclass and queue it up in the event queue. Now you know what’s inside an event loop :)What requires a running event loop?
This isn’t an exhaustive list, but if you have the overall picture, you should be able to guess which classes require a running event loop.
*Widgets painting and interaction: QWidget::paintEvent() will be called when delivering QPaintEvent objects, which are generated both by calling QWidget::update() (i.e. internally) or by the window manager (for instance, because a hidden window was shown). The same thing holds for all kinds of interaction (keyboard, mouse, etc.): the corresponding events will require an event loop to be dispatched.
*Timers: long story short, they’re fired when select(2) or similar calls time out, therefore you need to let Qt do those calls for you by returning to the event loop.
*Networking: all low-level Qt networking classes (QTcpSocket, QUdpSocket, QTcpServer, etc.) are asynchronous by design. When you call read(), they just return already available data; when you call write(), they schedule the writing for later. It’s only when you return to the event loop the actual reading/writing takes place. Notice that they do offer synchronous methods (the waitFor* family of methods), but their use is discouraged because they block the event loop while waiting. High-level classes, like QNetworkAccessManager, simply do not offer any synchronous API and require an event loop.Blocking the event loop
Before discussing why you should never ever block the event loop, let’s try to figure out what this ’blocking’ means. Suppose you have a Button widget which emits a signal when clicked; connected to this signal there’s a slot of our Worker object, which does a lot of work. After you click the button, the stack trace will look like this (the stack grows downwards):
*main(int, char )
*QApplication::exec()
*[…]
*QWidget::event(QEvent )
*Button::mousePressEvent(QMouseEvent)
*Button::clicked()
*[…]
*Worker::doWork()
In main() we started the event loop, as usual, by calling QApplication::exec() (line 2). The window manager sent us the mouse click, which was picked up by the Qt kernel, converted in a QMouseEvent and sent to our widget’s event() method (line 4) by QApplication::notify() (not shown here). Since Button didn’t override event(), the base class implementation (QWidget) is called. QWidget::event() detects the event is actually a mouse click and calls the specialized event handler, that is, Button::mousePressEvent() (line 5). We overrode this method to emit the Button::clicked() signal (line 6), which invokes the Worker::doWork slot of our worker object (line 7).
While the worker is busy working, what’s the event loop doing? You should’ve guessed it: nothing! It dispatched the mouse press event and it’s blocked waiting for the event handler to return. We managed to block the event loop, which means that no event is sent any more, until we return from the doWork() slot, up the stack, to the event loop, and let it process pending events.
With the event delivery stuck, widgets won’t update themselves (QPaintEvent objects will sit in the queue), no further interaction with widgets is possible (for the same reason), timers won’t fire and networking communications will slow down and stop. Moreover, many window managers will detect that your application is not handling events any more and tell the user that your application isn’t responding. That’s why is so important to quickly react to events and return to the event loop as soon as possible!Forcing event dispatching
So, what do we do if we have a long task to run and don’t want to block the event loop? One possible answer is to move the task into another thread: in the next sections we’ll see how to do that. We also have the option to manually force the event loop to run, by (repeatedly) calling QCoreApplication::processEvents() inside our blocking task. QCoreApplication::processEvents() will process all the events in the event queue and return to the caller.
Another available option we can use to forcibly reenter the event loop is the QEventLoop class. By calling QEventLoop::exec() we reenter the event loop, and we can connect signals to the QEventLoop::quit() slot to make it quit. For instance:
QNetworkAccessManager qnam;QNetworkReply *reply = qnam.get(QNetworkRequest(QUrl(…)));QEventLoop loop;QObject::connect(reply, SIGNAL (finished()), &loop, SLOT (quit()));loop.exec();/* reply has finished, use it */
QNetworkReply doesn’t offer a blocking API and requires an event loop to be running. We enter a local QEventLoop, and when the reply has finished, the local event loop quits.
Be very careful when reentering the event loop ’by other paths’: it can lead to unwanted recursions! Let’s go back to the Button example. If we call QCoreApplication::processEvents() inside the doWork() slot, and the user clicks again on the button, the doWork() slot will be invoked again:
*main(int, char)
*QApplication::exec()
*[…]
*QWidget::event(QEvent )
*Button::mousePressEvent(QMouseEvent)
*Button::clicked()
*[…]
*Worker::doWork() // first, inner invocation
*QCoreApplication::processEvents() // we manually dispatch events and…
*[…]
*QWidget::event(QEvent * ) // another mouse click is sent to the Button…
*Button::mousePressEvent(QMouseEvent *)
*Button::clicked() // which emits clicked() again…
*[…]
*Worker::doWork() // DANG! we’ve recursed into our slot.
A quick and easy workaround for this is passing QEventLoop::ExcludeUserInputEvents to QCoreApplication::processEvents(), which tells the event loop to not dispatch any user input event (the events will simply stay in the queue).
Luckily, the same thing does not apply to deletion events (the ones posted in the event queue by QObject::deleteLater()). In fact, they are handled in a special way by Qt, and are processed only if the running event loop has a smaller degree of ’nesting’ (w.r.t. event loops) than the one where deleteLater was called. For instance:
QObject *object = new QObject;object->deleteLater();QDialog dialog;dialog.exec();
will not make object a dangling pointer (the event loop entered by QDialog::exec() is more nested than the deleteLater call). The same thing applies to local event loops started with QEventLoop. The only notable exception I’ve found to this rule (as of Qt 4.7.3) is that if deleteLater is called when NO event loop is running, then the first event loop entered will pick up the event and delete the object. This is pretty much reasonable, since Qt does not know about any ’outer’ loop that will eventually perform the deletion, and therefore deletes the object immediately.
.
A computer is a state machine. Threads are for people who can’t program state machines.
— Alan Cox
Qt has had thread support for many years (Qt 2.2, released on 22 Sept 2000, introduced the QThread class.), and with the 4.0 release thread support is enabled by default on all supported platforms (although it can be turned off, see here for more details). Qt now offers several classes for dealing with threads; let’s start with an overview.QThread
QThread is the central, low-level class for thread support in Qt. A QThread object represents one thread of execution. Due to the cross-platform nature of Qt, QThread manages to hide all the platform-specific code that is needed to use threads on different operating systems.
In order to use a QThread to run some code in a thread, we can subclass it and override the QThread::run() method:
class Thread : public QThread {protected:
};
Then we can use
Thread *t = new Thread;t->start(); // start(), not run()!
to actually start the new thread. Note that since Qt 4.4 QThread is no longer an abstract class; now the virtual method QThread::run() instead simply calls QThread::exec();, which starts the thread’s event loop (more info on this later).
QRunnable and QThreadPool
QRunnable is a lightweight abstract class that can be used to start a task in another thread in a ’run and forget’ fashion. In order to do so, all we have to do is subclass QRunnable and implement its run() pure virtual method:
class Task : public QRunnable {public:
};
To actually run a QRunnable object we use the QThreadPool class, which manages a pool of threads. By calling QThreadPool::start(runnable) we put a QRunnable in a QThreadPool’s runqueue; as soon as a thread becomes available, the QRunnable will be picked up and run into that thread. All Qt applications have a global thread pool available by calling QThreadPool::globalInstance(), but one can always create a private QThreadPool instance and manage it explicitely.
Notice that, not being a QObject, QRunnable has no built-in means of explicitely communicating something to other components; you have to code that by hand, using low-level threading primitives (like a mutex-guarded queue for collecting results, etc.).QtConcurrent
QtConcurrent is a higher-level API, built on top of QThreadPool, useful to deal with the most common parallel computation patterns: map, reduce, and filter ; it also offers a QtConcurrent::run() method that can be used to easily run a function in another thread.
Unlike QThread and QRunnable, QtConcurrent does not require us to use low-level synchronization primitives: all QtConcurrent methods instead return a QFuture object, which can be used to query the computation status (its progress), to pause/resume/cancel the computation, and that also contains its results. The QFutureWatcher class can be used to monitor a QFuture progress and interact with it by means of signals and slots (notice that QFuture, being a value-based class, doesn’t inherit QObject).Feature comparisonQThreadQRunnableQtConcurrent[1]High level API✘✘✔Job-oriented✘✔✔Builtin support for pause/resume/cancel✘✘✔Can run at a different priority✔✘✘Can run an event loop✔✘✘Per-thread event loop
So far we’ve always talked about ’the event loop’, taking somehow per granted that there’s only one event loop in a Qt application. This is not the case: QThread objects can start thread-local event loops running in the threads they represent. Therefore, we say that the main event loop is the one created by the thread which invoked main(), and started with QCoreApplication::exec() (which must be called from that thread). This is also called the GUI thread, because it’s the only thread in which GUI-related operations are allowed. A QThread local event loop can be started instead by calling QThread::exec() (inside its run() method):
class Thread : public QThread {protected:
exec();
};
As we mentioned before, since Qt 4.4 QThread::run() is no longer a pure virtual method; instead, it calls QThread::exec(). Exactly like QCoreApplication, QThread has also the QThread::quit() and QThread::exit() methods to stop the event loop.
A thread event loop delivers events for all QObjects that are living in that thread; this includes, by default, all objects that ar
https://diarynote-jp.indered.space
コメント