How to properly stop QThread run() function? - multithreading

I have one thread, producer and class consumer. Consumer is registered in QML, and producer is connected with signals to consumer. Producer send data to consumer, so consumer can update the model and GUI.
Code looks something like this:
Main function:
int main(int argc, char ** argv)
{
QGuiApplication app(argc, argv);
Producer producer;
Consumer consumer;
/* Connect signals between producer and consumer */
...
...
QQuickView view;
/* Set root context */
QQmlContext *ctxt = view.rootContext();
producer.start();
ctxt->setContextProperty("consumer", &consumer);
/*Connect signals between consumer and QML*/
...
view.show();
return app.exec();
}
Producer:
class Producer : public QThread
{
Q_OBJECT
protected:
void run()
{
while(true) {
if (someFlag == true)
{
// do some work
// emit signal with data to consumer
}
}
}
signals:
// Signals for sending data
};
The question is how to properly stop thread Producer when exit in application is pressed?

Instead of while(true) check for a "should end" condition, e.g. isInterruptionRequested().
Then, in main(), before returning, you tell the thread to stop, e.g. with QThread::requestInterruption and then wait on the thread
view.show();
const int ret = app.exec();
producer.requestInterruption();
producer.wait();
return ret;

I have a suggestion:
My way of doing is, Register the windows close event and do any sort of cleaning activities in it.
pseudo code below. try to fit it in your application.
Close filter event:
class CloseEventFilter : public QObject
{
Q_OBJECT
public:
CloseEventFilter(QObject *parent) : QObject(parent) {}
protected:
bool eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::Close)
{
// Destroy your thread here.
producer->exit();//Make your thread available
//... may be global....producer is derived from QThread.
}
return QObject::eventFilter(obj, event)
}
}
};
Registering to windows
//Registering window
QGuiApplication *app = new QGuiApplication(argc,argv);
QWindow* qtwindow = new QWindow();
CloseEventFilter *closeFilter = new CloseEventFilter(window);
qtwindow >installEventFilter(closeFilter);
Why thread exit funtion (from documentation)
void QThread::exit(int returnCode = 0)
Tells the thread's event loop to exit with a return code.
After calling this function, the thread leaves the event loop and returns from the call to QEventLoop::exec(). The QEventLoop::exec() function returns returnCode.
By convention, a returnCode of 0 means success, any non-zero value indicates an error.
Note that unlike the C library function of the same name, this function does return to the caller -- it is event processing that stops.
No QEventLoops will be started anymore in this thread until QThread::exec() has been called again. If the eventloop in QThread::exec() is not running then the next call to QThread::exec() will also return immediately.
See also quit() and QEventLoop.

The while (true) if (someFlag) loop will peg the CPU at 100% when there's no work to be done. You don't want that!
Alas, there's no need to make the Producer be a QThread. It can be a plain old QObject. There are different ways of doing it.
You can use a zero-duration timer to keep the event loop active in the thread:
class Producer : public QObject
{
Q_OBJECT
QBasicTimer m_timer;
void timerEvent(QTimerEvent * ev) override {
if (ev->timerId() == m_timer.timerId())
doWorkChunk();
}
void doWorkChunk() {
...
emit hasData(...);
}
public:
Producer(QObject * parent = nullptr) : QObject{parent} {
connect(this, &Producer::start, this, [this]{ m_timer.start(this, 0); });
connect(this, &Producer::stop, this, [this]{ m_timer.stop(); });
}
Q_SIGNAL void start();
Q_SIGNAL void stop();
Q_SIGNAL void hasData(const DataType &);
};
Instead of setting/clearing the flag, call start() and stop(). Then you can move the producer to any thread and it will work just fine, doing the right thing on exit (wrapping things up cleanly):
class Thread : public QThread {
using QThread::run;
public:
~Thread() { quit(); wait(); }
};
int main(int argc, char ** argv) {
QCoreApplication app{argc, argv};
Producer producer;
Thread thread; // must come after producer above, the order has meaning!
producer.moveToThread(&thread);
thread.start();
return app.exec();
}
You can use the Qt Concurrent framework, too:
class Producer : public QObject {
{
Q_OBJECT
volatile bool m_active = false;
void doWorkChunk() {
...
emit hasData();
}
void doWork() {
while (m_active) doWorkChunk();
}
public:
using QObject::QObject;
~Producer() { stop(); }
void start() {
m_active = true;
QtConcurrent::run(this, &Producer::doWork);
}
void stop() {
m_active = false;
}
Q_SIGNAL void hasData(const DataType &);
};

Related

One thread with multiple worker processes?

I'm wondering whats the procedure for having one thread and belonging to that thread one worker which has multiple processes. If that doesn't make too much sense hopefully the code below should explain:
// WORKER.H //
class Worker : public QObject
{
Q_OBJECT
Public:
Worker(QObject *parent = nullptr);
Public Slots:
void process1(int x);
void process2(int y);
void process3(int z);
signals:
void sendResult(int result);
}
// CONTROLLER.H //
class controller : public QObject
{
Q_OBJECT
public:
controller(QObject *parent = nullptr);
signals:
operate();
public slots:
void storeResults(const int);
private:
QThread myThread;
}
// CONTROLLER.CPP // I shall only give the constructor
Controller::Controller(QObject *parent) : QObject(parent)
{
Worker *worker = new Worker;
worker->moveToThread(&myThread);
//connections
connect(&myThread, &QThread::finished, worker, &QObject::deleteLater);
connect(this, &Controller::operate, worker, &Worker::process1);
connect(this, &Controller::operate, worker, &Worker::process2);
connect(this, &Controller::operate, worker, &Worker::process3);
connect(worker, &Worker::sendResult, this, &Controller::storeResult);
myThread.start();
}
What I'm hoping to achieve here is a system where the three processes slots in the worker class will receive data from signals from the GUI. these signals will be constantly being received throughout the life of the program. Once a given signal is received, it shall be processed, and the result of the processing will be emitted into the store result slot.
Would this code achieve what I expect or is there something I'm overlooking?
Many Thanks

QProcess in thread works but with two type output errors

I'am learning QT multithreading.
With the following code, it works ok, but there are two type errors
The code is too simple to figure out what's going wrong.
CmdController(Controller thread) -> CMD(Ping test thread) -> QProcess(excute "ping")
main.c
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// create Test object, and then execute “ping” cmd under windows
CmdController Test;
Test.process();
return a.exec();
}
CmdController.h
// deal with "ping" command
class Cmd : public QObject
{
Q_OBJECT
public:
explicit Cmd();
private:
QProcess CmdExe;
public slots:
void process();
void readFromStdOut();
};
// Controller class
class CmdController : public QObject
{
Q_OBJECT
public:
explicit CmdController();
~CmdController();
signals:
void process();
private:
QThread mThread;
Cmd mCmd;
};
CmdController.c
Cmd::Cmd()
{
connect(&CmdExe, SIGNAL(readyReadStandardOutput()), this, SLOT(readFromStdOut()));
}
void Cmd::process()
{
CmdExe.start("ping", {"www.baidu.com"});
}
void Cmd::readFromStdOut()
{
QByteArray resault = CmdExe.readAllStandardOutput();
qDebug() << QTextCodec::codecForName("GBK")->toUnicode(resault);
}
CmdController::CmdController()
{
mCmd.moveToThread(&mThread);
connect(this, &CmdController::process, &mCmd, &Cmd::process);
mThread.start();
}
CmdController::~CmdController()
{
mThread.exit();
mThread.wait();
}
The output:
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QProcess(0x6ffdf0), parent's thread is QThread(0x1f6510), current thread is QThread(0x6ffdd0)
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QProcess(0x6ffdf0), parent's thread is QThread(0x1f6510), current thread is QThread(0x6ffdd0)
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QProcess(0x6ffdf0), parent's thread is QThread(0x1f6510), current thread is QThread(0x6ffdd0)
"\r\n正在 Ping www.a.shifen.com [180.101.49.42] 具有 32 字节的数据:\r\n"
"来自 180.101.49.42 的回复: 字节=32 时间=31ms TTL=53\r\n"
"来自 180.101.49.42 的回复: 字节=32 时间=31ms TTL=53\r\n"
"来自 180.101.49.42 的回复: 字节=32 时间=30ms TTL=53\r\n"
"来自 180.101.49.42 的回复: 字节=32 时间=30ms TTL=53\r\n\r\n180.101.49.42 的 Ping 统计信息:\r\n 数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),\r\n往返行程的估计时间(以毫秒为单位):\r\n 最短 = 30ms,最长 = 31ms,平均 = 30ms\r\n"
QObject::connect: Cannot queue arguments of type 'HANDLE'
(Make sure 'HANDLE' is registered using qRegisterMetaType().)
Error 1st:
1-6 lines output error, shows creating children object fails, by three times.
The ping test is ok.
so, who cause the error?
QThread(0x6ffdd0) is Cmd-object,
QThread(0x1f6510) is CmdController-object,
QProcess(0x6ffdf0) clearly is QProcess-object,
does it mean the QProcess, try to create something?
Error 2ed:
last two lines.
googled, cann't find 'HANDLE' what it is.
If if remove multithreading stuff from
CmdController(Controller thread) -> CMD(Ping test thread) -> QProcess(excute "ping")
to
CmdController(Controller thread) -> QProcess(excute "ping")
there will be no error, everything works perfectly.
I'am confused.
Thank you.
To understand the problem, one must first be clear that a QObject must be executed only in the thread to which it belongs, if another thread is executed then Qt does not guarantee that it works, and that is what has happened in this case.
Let's analyze to which thread each QObject belongs, by default QObject belongs to the thread where it was created or to the thread of its father, so when you create the object "Test" this belongs the main thread, the object "mCmd" at the beginning belongs to the main thread and then you move it to "mThread", "CmdExe" belongs to the thread where it was created, that is to say to the main thread but the "Cmd" process method is executed in the secondary thread but "CmdExe" is executed in the main thread causing the problem.
The solution is to make "CmdExe" the son of "Cmd" so that both belong to the same thread and not generate problems.
// ...
class Cmd : public QObject
{
Q_OBJECT
public:
explicit Cmd(QObject *parent=nullptr);
private:
QProcess *CmdExe;
public slots:
void process();
void readFromStdOut();
};
// ...
// ...
Cmd::Cmd(QObject *parent):QObject(parent), CmdExe(new QProcess(this))
{
connect(CmdExe, &QProcess::readyReadStandardOutput, this, &Cmd::readFromStdOut);
}
void Cmd::process()
{
CmdExe->start("ping", {"www.baidu.com"});
}
// ...

Play QSoundEffect in QThread

I can not get the QSoundEffect to play in a separate thread. Could you please tell me why is the sound played only by the first code snippet and not by the second?
//main.cpp
#include <QCoreApplication>
#include "SoundThread.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// #1
QSoundEffect alarmSound;
alarmSound.setSource(QUrl::fromLocalFile(":/sound"));
alarmSound.play();
/* #2
SoundThread thread;
thread.start();
thread.wait();
*/
return a.exec();
}
and
//SoundThread.h
#ifndef SOUNDTHREAD_H
#define SOUNDTHREAD_H
#include <QThread>
#include <QtMultimedia/QSoundEffect>
class SoundThread : public QThread
{
Q_OBJECT
private:
void run()
{
QSoundEffect alarmSound;
alarmSound.setSource(QUrl::fromLocalFile(":/sound"));
alarmSound.play();
while(true){}
}
};
#endif // SOUNDTHREAD_H
From the Qt documentation on QThread: -
By default, run() starts the event loop by calling exec()
Since you've inherited from QThread, you now have a run function which doesn't call exec(). Therefore, the event loop is not running and is most likely required for playing the sound effect.
Calling exec() should be substituted for the while(true){} as exec() will wait until exit() is called.
Doing it properly, with moving an object to the thread, based on "How to Really Truly Use QThreads..."
class Worker : public QObject
{
Q_OBJECT
public:
Worker();
~Worker();
public slots:
void PlaySoundEffect();
signals:
void finished();
void error(QString err);
private:
// store the sound effect, so we can reuse it multiple times
QSoundEffect* m_pAlarmSound;
private slots:
};
Worker::Worker()
{
m_pAlarmSound = new QSoundEffect;
m_pAlarmSound.setSource(QUrl::fromLocalFile(":/sound"));
}
Worker::~Worker()
{
delete m_pAlarmSound;
m_pAlarmSound = nullptr; // C++ 11
}
void Worker::PlaySoundEffect()
{
m_pAlarmSound->play();
}
// setup the worker and move it to another thread...
MainWindow::MainWindow
{
QThread* thread = new QThread;
Worker* worker = new Worker();
worker->moveToThread(thread);
connect(worker, SIGNAL(error(QString)), this, SLOT(errorString(QString)));
connect(thread, SIGNAL(started()), worker, SLOT(PlaySoundEffect()));
connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
// We can also connect a signal of an object in the main thread to the PlaySoundEffect slot
// Assuming MainWindow has declared a signal void Alert();
connect(this, &MainWindow::Alert, worker, &Worker::PlaySoundEffect);
// Then play the sound when we want: -
emit Alert();
}
While this seems like a lot of effort, there are many advantages of doing it this way. If, for example, you have a lot of sound effects, the method of inheriting QThread means that you're creating a thread per sound effect, which isn't ideal.
We could easily extend the above Worker object to hold a list of sound effects and play the one we want, by passing an enum into the PlaySoundEffect slot. As this thread is constantly running, playing sounds will incur less delay; it takes time and resources to create a thread at run-time.
You enter to an infinite loop at the end of your run function which causes to block the thread and consequently the QSoundEffect not working. It should be like:
void run()
{
QSoundEffect alarmSound;
alarmSound.setSource(QUrl::fromLocalFile(":/sound"));
alarmSound.play();
exec();
}
Replace while(true){} by QThread::run();, which will launch an internal event loop and will wait (sleep) for events, such as timer events and asynchronous signals calling slots, which is probably what is happening internally in QSoundEffect: When you call QSoundEffect::play() Some event (probably signals/slots) are queued in the event queue from within QThread, but nothing is processing the event queue. Remember: you are overriding virtual void run() and the original implementation was calling QThread::exec() for you. It is always a good idea to always call your super classes virtual function whenever you override them, as long as they are not pure virtual.
void run()
{
QSoundEffect alarmSound;
alarmSound.setSource(QUrl::fromLocalFile(":/sound"));
alarmSound.play();
QThread::run();
}
Some people suggested that calling QThread::exec() would do the trick. They may be right. I have to check the implementation of QThread to confirm that it is the only thing called in QThread::run() implementation. I personally think (by experience) that it is always safer to call your superclasse's virtual function in case there are other things called (other than QThread::exec() for this particular case).
Another option would be to move your QSoundEffect instance onto the thread and use signals and slots default auto-connection behaviour type to switch threads.
SoundPlayer.h:
#ifndef SOUNDPLAYER_H_
#define SOUNDPLAYER_H_
#include <QObject>
#include <QThread>
#include <QSoundEffect>
class SoundPlayer : public QObject
{
Q_OBJECT
public:
SoundPlayer();
signals:
void play();
private:
QThread m_thread;
QSoundEffect m_alarmSound;
};
#endif
SoundPlayer.cpp :
#include "SoundPlayer.h"
SoundPlayer()
{
m_alarmSound.setSource(QUrl::fromLocalFile(":/sound"));
m_alarmSound.moveToThread(&m_thread);
connect(this, SIGNAL(play()), &m_alarmSound, SLOT(play()));
m_thread.start(); // QThread::exec() will be called for you, making the thread wait for events
}
And then calling the play() signal would start playing in the correct thread.
SoundPlayer player;
emit player.play(); // m_alarmSound.play() will be called by m_thread

How to overcome the Qthread synchronization issue here?

I have a main thread that loads the web-page and displays it. I have another thread running, that will just print the debug message on to the console.However, I am seeing that on running the QT-Thread, the web-page is not getting loaded. I tried putting the loading of web-page on to the constructor of thread, but this is also not helping here.Here is the code.
class MyJavaScriptOperations : public QObject {
Q_OBJECT
public:
Q_INVOKABLE qint32 MultOfNumbers(int a, int b) {
qDebug() << a * b;
return (a*b);
}
};
#if 1
class MyThread : public QThread
{
Q_OBJECT
public:
MyThread();
public:
void run();
};
MyThread::MyThread()
{
qDebug()<<"Constructor called";
QWebView *view = new QWebView();
view->resize(400, 500);
view->page()->mainFrame()->addToJavaScriptWindowObject("myoperations", new MyJavaScriptOperations);
view->load(QUrl("./shreyas.html"));
view->show();
this->run();
}
void MyThread::run()
{
qDebug()<<"Thread running";
while(1)
{
qDebug()<<"Fire Callback now";
}
}
#endif
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyThread t;
//t.run();
return a.exec();
}
Just because code is in a subclass of QThread doesn't mean that code is executed in that thread. Your main thread constructs the object, and that constructor calls run(). This means that the code of the run method is still executed in the main thread, and - as it is blocking - the line a.exec() is never called, and the main thread never gets an event loop which is required for paint events and the like.
What you need to do is start the thread and wait for run() being executed:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// TODO: Code for your web view goes here. You will probably need to
// pass the created web view into the constructor of MyThread
MyThread t;
// start the thread - this will put an event in the main event loop
t.start();
// start the event loop - this will lead to MyThread::run() being called
return a.exec();
}
This is enough to get your example running, but you will get errors when closing the web view as your way of using threads is not the intended one: If you want to make your code stable, put the code of your run() method in a separate worker class and use a default QThread for managing that, without subclassing QThread.
I recommend reading the Qt5 Documentation on threads, which is also applicable for earlier versions of Qt.

Working with threads in blackberry

I am using threads in blackberry to perform web service calls. I want to get notified as soon as the call gets a response back. I was using
Handlers
in android. I didnt find anything similar in blackberry.
Here is the code I am using to run the thread
class PrimeRun implements Runnable {
long minPrime;
PrimeRun(long minPrime) {
this.minPrime = minPrime;
}
public void run() {
// compute primes larger than minPrime
. . .
}
}
How can I get a notification after the thread finished running?
How can I do this in blackberry?
Thanks
Added more Information : Thanks for your reply. Its really
informative. Let me explain a bit more on my issue. I have a
webservice call which is running on a thread. As soon as I get the
reply back from server I want to execute the next function(next call
to server) which is based on the response from the previous call.So I need to wait until I get a response back. Also
at them same time I need to show a activity indicator on screen. I was
using handler for this in android. I am looking for something similar
on blackberry.
So your question essentially is this
One thread does the job while the other thread waits for completion
The first thread completes the job and "notifies" the second thread.
This is a simple producer consumer problem. Here is the code how you can solve this.
class JobResult
{
boolean done = false;
}
JobResult result = new JobResult();
class Worker extends Thread
{
JobResult _result;
public Worker( JobResult result )
{
_result = result
}
public void run()
{
// Do some very long job
synchronized( _result )
{
// modify result
_result.done = true;
_result.notify();
}
}
}
public class Waiter extends Thread
{
JobResult _result;
public Waiter( JobResult result )
{
_result = result;
}
public void run()
{
synchroinzed( _result ){
while(! _result.done)
{
this.wait();
}
}
// Wait is over. You can do something now.
}
}
As I got the Zach's question - he asks how to execute some code that involves UI changes (something like showing an info popup or closing the progress popup) upon a background thread completion. On Android a Handler created on the UI thread is often used for that purpose.
In BB you can use another way which is similar to Swing on desktop Java. When you need some code to be executed on the UI thread you wrap it in a Runnable and pass to one of the following methods:
// Puts runnable object into this application's event queue,
// and waits until it is processed.
Application.invokeAndWait(Runnable runnable)
// Puts runnable object into this application's event queue.
Application.invokeLater(Runnable runnable)
// Puts runnable object into this application's event queue
// for repeated execution.
Application.invokeLater(Runnable runnable, long time, boolean repeat)
So the behaviour of the above calls is similar to what Handler.post(Runnable r) (and the like) does.
Note, you can always get a handle to your Application instance by a static call Application.getApplication().
So in the end of a background thread it is safe to do something like this:
Application.getApplication().invokeLater(new Runnable() {
public void run() {
progressScreen.close();
Dialog.alert("I am finished!");
}
});
It is similar to Android's:
handler.post(new Runnable() {
public void run() {
progressScreen.dismiss();
showDialog(DIALOG_TASK_FINISHED_ID);
}
});
Android has a much rich multi threading primitives. But you can achieve the same even in Blackberry with equal elegance. The solution I provide below is essentially the same as previous, but with a minor change. Waiter thread can be replaced with built-in utility to perform painting on UI thread using UiApplicaiton's invokeLater method. You don't actually need to "notify" anyone but just update the UI once a particular task is completed. Check the docs for more info.
Anyway, you can model your code along the lines:
class ProgressScreen extends FullScreen
{
LabelField _label;
public void start()
{
}
public void setMessage( final String message )
{
UiApplication.getApplication(
UiApplication.invokeLater(
new Runnable() {
_label.setText( message );
}
)
);
}
public void dismiss()
{
this.close();
}
}
interface WebserviceTask
{
int STATUS_CONDITIONS_NOT_SATISFIED = -3;
int STATUS_NET_ERR = -2;
int STATUS_FAILURE = -1;
int STATUS_SUCCESS = 0;
public int invoke();
}
public class Updater extends Thread
{
final int NUM_TASKS = 10;
WebServiceTask tasks[] = new WebServiceTask[ NUM_TASKS ];
WebServiceTask tasks[0] = new WebServiceTask(){
public int invoke()
{
int retCode = 0;
// invoke a particular web service
return STATUS_SUCCESS;
}
}
public void run()
{
ProgressScreen progress = new ProgressScreen();
progress.start();
for( int i=0; i < NUM_TASKS; i++ )
{
int retcode;
WebServiceTask t = tasks[i];
retcode = t.invoke();
String mesg;
switch( retcode )
{
case STATUS_SUCCESS: { mesg ="Task successfully completed!";} break;
case STATUS_NET_ERR: { mesg ="Could not connect to network";} break;
}
progress.setMessage(message);
}
progress.dismiss();
}
}
Note that I have provided only the stubs to give you an idea how you may accomplish. Let us know how it goes.

Resources