I would like manage a set of application requirements. Each requirement have a state (Accepted, Rejected, InProgress), and a message state. Some toolbuttons have to be enabled just if all the requirements are accepted.
All the requirements are viewed in a tableview (two colums : name and state message), with an icon state for each line.
A requirement is checked by a separated worker. I do this with QtConcurrent/QThreadPool. But I have to know when the pool have finished all the checks.
There's no signal finished in QThreadPool...
Maybe I do it wrong. Any idea, link or example are welcom !
If you use QtConcurrent, you should use QFutureWatcher to get finished signal.
If it's not possible, you can start another thread and call pool->waitForDone() and emit custom signal. Of course this thread must not be in the same pool. Alternatively, you can setup a QTimer with small interval and use bool finished = pool->waitForDone(1); to periodically check if the pool has been finished.
When you inherit QRunnable yuo can also add inheritance of QObject (as first) and emit signal at the end of run.
class YourTask : public QObject, public QRunable {
Q_OBJECT
public:
explicit YourTask(QObject *parent = 0);
void run();
};
QFutureWatcher is cool when you use future (see another answer).
Related
I want to show a widget for displaying an animated loading gif while another function (pthread) computes a task.
I have tried to subclass my widget with a QThread class, and implemented the method run() where I call the method show(). However, my widget GUI froze.
How can I launch a widget where the GUI is processed separately?
You can't have widgets running on anything except the main thread.
Also, unless you're wanting to change how Qt handles threads, you should not be inheriting from QThread.
Instead, create a worker object that inherits from QObject and move that to the new thread. You can read how to really use QThread here.
Your worker object can then be moved to another thread, do its computation and communicate to the Gui widgets, on the main thread, via signals and slots.
For example, here's a brief outline of a worker class: -
class Worker : public QObject
{
Q_OBJECT
signals:
void finished();
void displayWidget();
private slots:
void run();
}
QThread pThread = new QThread;
Worker pObject = new Worker;
// move the pObject to the thread
pObject->moveToThread(pThread);
You can then control the thread with signals and slots.
// assuming you've added a run slot function to the Consumer class
connect(pThread, SIGNAL(started()), pObject, SLOT(run()));
connect(pObject, SIGNAL(finished()), pThread, SLOT(quit()));
connect(pObject, SIGNAL(finished()), pObject, SLOT(deleteLater()));
// Note the thread cleans itself up here, but if the app is quitting,
// waiting on the thread to finish may be required instead
connect(pThread, SIGNAL(finished()), pThread, SLOT(deleteLater()));
And start the thread: -
pThread->start();
Used this way, it also enables multiple objects to be moved to a single new thread, rather than creating a new thread per object instance.
So now, for example, if you wanted to display a widget at some point during the processing in the worker object, you'd emit its displayWidget() signal, having previously connected it to the Widget's show() slot.
QWidget* pWidget = new QWidget(parent); // assumes parent is initialized
// using Qt 5 connect call
connect(pWorker, &Worker::displayWidget, pWidget, &Widget::show);
You can't use QWidget (nor any derived classes) directly from threads other than the GUI thread. All you can do directly is to use a QImage owned by the worker thread and paint on it directly from that thread. Here, directly means that you are simply calling methods of objects.
What you need is a way to execute show() not directly in the invoking thread, but indirectly within the GUI thread's context. This is quite simple since QWidget::show() is a slot. Thus, from your computation thread, simply do:
QMetaObject::invokeMethod(widget, "show");
That's all. The implementation of invokeMethod will determine that widget lives in a different thread, and will automatically choose the QueuedConnection method of call delivery. Internally, it will post a QMetaCallEvent to widget. The widget's QObject::event method will act on the event and place the call to the show method. This will happen in the GUI thread.
You can use the same approach to set QProgressBar, for example:
int value = ...;
QMetaObject::invokeMethod(progressBar, "setValue", Q_ARG(int, value));
I have a condition where I have unknown amount of 3rd party threads calling a callback in my application. That callback emits a signal in the context of the threads that called it. Always the same signal, but 10 different threads can emit it at any given moment.
I'd like to queue all of those singlas and process them with the appropriate slot in the context of a single QThread I own.
How do I do that? The following code does not work. Although I see it signals being emitted, from different threads, my "On..." is never called.
QObject::connect(this,SIGNAL(ProcessQueuedOutEvent(int)),
this,
SLOT(OnProcessQueuedOutEvent(int)),
Qt::QueuedConnection);
Does your QThread run the event loop? It has to do it to receive signals:
Queued Connection The slot is invoked when control returns to the
event loop of the receiver's thread. The slot is executed in the
receiver's thread.
Basically queued connection works the following way:
The originator issues a signal.
Qt creates an event and posts it into the receiver event queue.
The receiver goes through its event queue, picks up the events and dispatches the signals into the connected slots.
Hence if you do not run the event queue, the signals are posted but your thread will never receive them.
So basically your thread should do some initialization in run() but then call exec() and pass it to Qt.
If your thread also needs to run some periodic operations besides checking for signals, you can do that by using QTimer::singleShot timers posting signals to the same thread.
See http://qt-project.org/doc/qt-4.8/threads-qobject.html#signals-and-slots-across-threads
PS. If you pass the pointers via queued connections, the pointer must be valid until the signal is processed, which may be after your function which posted the signal existed. A common error is to post signals with strings as a parameters which are stored in a local char[] buffer. At the moment the buffer is accessed the original function is finished, and the string is already gone. Those errors depend on thread scheduling and therefore hard to debug. If you pass the pointers via queued connection, they must be heap-allocated and the callee must be responsible to free them.
If I understand your problem correctly, you have a callback function executed by many threads. This callback function should emit a signal connected to a slot in a object which is in another thread.
What I suggest is to create a threaded receiver object, using the pattern (moveToThread). Then using the postEvent method to a private implementation method. The call is thread safe (the parameter is copied).
So your callbacks can directly and safely call:
OnProcessQueuedOutEvent
which posts an event to the QThread event loop.
Receiver.h
class Receiver : public QObject
{
Q_OBJECT
public:
explicit Receiver( QObject* parent = 0 );
virtual ~Receiver();
public slots:
void OnProcessQueuedOutEvent( int val );
private slots:
void OnProcessQueuedOutEventImpl( int val );
private:
QThread m_thread;
};
Receiver.cpp
Receiver::Receiver( QObject* parent )
: QObject(parent)
{
moveToThread(&m_thread);
m_thread.start();
}
Receiver::~Receiver()
{
// Gracefull thread termination (queued in exec loop)
if( m_thread.isRunning() ) {
m_thread.quit();
m_thread.wait();
}
}
void OnProcessQueuedOutEvent( int val )
{
QMetaObject::invokeMethod(this, "OnProcessQueuedOutEventImpl", Q_ARG(int,val));
}
void OnProcessQueuedOutEventImpl( int val )
{
// do stuff here
}
I am trying to modify the Qt Fortune Threaded Server example to read text from the connection and then echo it back. I defined tcpSocket in my FortuneThread.h file as follows:
QTcpSocket tcpSocket;
My new run function for the thread looks as follows:
void FortuneThread::run()
{
if (!tcpSocket.setSocketDescriptor(socketDescriptor)) {
emit error(tcpSocket.error());
return;
}
connect(&tcpSocket, SIGNAL(readyREAD()), this, SLOT(readCommand()) );
}
Which compiles and runs, but once I connect I get this error (referring to the connect line):
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QTcpSocket(0x1eeb920), parent's thread is QThread(0x1bb3f90), current thread is FortuneThread(0x1eeb8f0)
QObject::connect: No such signal QTcpSocket::readyREAD() in ../fortune/fortunethread.cpp:60
Can someone explain the cause to me? Since tcpSocket is defined inside the FortuneThread class (which is run as a separate thread), and "this" refers to FortuneThread, I assume both objects are inside the thread? How to fix this?
Your socket object has been created in the main thread, but you're accessing it from a different thread. You need to create it inside of the thread's run() method. The location where the socket is defined doesn't matter. It will be created from the main thread when the C++ runtime library is doing static object initialization.
QTcpSocket * tcpSocket;
...
void FortuneThread::run() {
tcpSocket = new QTcpSocket;
...
}
I agree with Kuba Ober. You should read that great guide about Qt threads, objects and events. In particular, section called Signals and slots across threads. Authors recommends split controller and work parts into different essences.
Second issue in your code — case sensitive signal name. Change it to readyRead.
A problem with the Qt Fortune Threaded Server example is the way in which it uses threads. As the developers of Qt say, "You're doing it wrong"
The issue is the inheritance of QThread. The QThread class is not actually a thread, but a thread controller class and the only reason to inherit this, is if you want to change the behaviour of controlling threads.
The problem you're seeing is due to thread affinity; which thread an object belongs to.
If a thread is inherited like this: -
class FortuneThread : public QThread
{
Q_OBJECT
private:
QTcpSocket tcpSocket;
};
An object of FortuneThread is then instantiated from the main thread: -
FortuneThread* ft = new FortuneThread(parent);
The thread affinity for the thread and the objects it has instantiated (tcpSocket) is now the main thread, so the tcpSocket is running on the main thread, which is what the error is stating. At the point the run function is called, the connect is coming from the FortuneThread, but the tcpSocket is on the main thread.
The better way to solve this is to create your class, derived from QObject and move it to the thread: -
// Inherit from QObject, not QThread
class FortuneSocket : public QObject
{
Q_OBJECT
public slots:
void Run();
private:
QTcpSocket tcpSocket;
};
QThread* pThread = new QThread(parent);
FortuneSocket* pFortune = new FortuneSocket(parent);
connect(pThread, &QThread::started, pFortune, &FortuneSocket::Run); // Qt5 connect style
// move the fortune socket to the thread: -
pFortune->moveToThread(pThread);
Now, when you start the thread with pThread->start(), the FortuneSocket object and all of its members are running on the new thread.
Using threads this way also means that you can move multiple objects to a single thread, rather than having one object per thread. Note that creating more threads than CPU cores is pointless!
Finally, there's a more in-depth article on how to use QThread, here.
First of all, forgive me if there’s an obvious solution, I’m completely new to the use of thread (and only know a bit about the theory).
I’m currently developing an application in which I want to use threads. Basically, it retrieves data an displays it on a graph in real time with Qt.
I’ve followed the guidelines of this post on how to use correctly QThread, but then I’m concerned with a few details.
Basically, I want to implement a pause, that will stop the real-time query and update, which can then be resumed later on.
At the moment, my class looks like this :
class DataProcessor : public QObject{
Q_OBJECT
public:
DataProcessor();
~DataProcessor();
//Internal details
public slots:
//mapped to the started() signal of a QThread
void process();
signals:
void finished();
void error(QString error);
}
I wonder how I could implement a pause feature. After reading Bruce Dawson’s post In praise of Idleness, I’ve noted a few methods that I should avoid (most importantly, avoiding busy wait)
Then, it doesn’t quite fit my needs, as Bruce talks about waiting for another thread to exit its critical section. Here, I just want to pause the work done by the thread’s worker on user input, and restart it the same way.
My question is: how can I implement an efficient pause for my threaded code ?
I’ve thought of using a sort of flag in my worker, that could be set from the main (something like bool m_paused;), but once set, I don’t know how I can actually pause efficiently my worker.
Note: This question was not written by me, but it describes my problem exactly. Source: link
Is there a way to detect when a QT QRunnable object is done? (Other than manually creating some signalling event at the end of the run() method.)
You can simply use QtConcurrent to run the runnable and use a QFuture to wait for finished.
#include <QtConcurrentRun>
class MyRunnable : public Runnable{
void run();
}
in order to run and wait for it you can do the following
//create a new MyRunnable to use
MyRunnable instance;
//run the instance asynchronously
QFuture<void> future = QtConcurrent::run(&instance, &MyRunnable::run);
//wait for the instance completion
future.waitForFinished();
Qtconcurrent::run will start a new thread to execute method run() on instance and immediately returns a QFuture that tracks instance progress.
Notice however that using this solution you are responsable to keep instance in memory during the execution.
There might be, or you might have to go a slight bit higher-level. The QFuture and QFutureWatcher classes are designed to work with Qt's Concurrent framework, and the QFutureWatcher class has a signal when the item it is watching has finished.
You can add your own SIGNAL which gets emitted as the last thing that your run() method does. Then simply connect it to coreesponding SLOT right before calling connect(...);