Launching a while-loop freezes program even if using another thread - c++

In my (Qt-)program I need a continuous request of a value which I get from an external source. But I did not want that this request freezes the whole program, so I created a separate thread for this function. But even if it is running in a separate thread, the GUI freezes, too. Why?
Code for the request function:
void DPC::run()
{
int counts = 0, old_counts = 0;
while(1)
{
usleep(50000);
counts = Read_DPC();
if(counts != old_counts)
{
emit currentCount(counts);
old_counts = counts;
}
}
}
Read_DPC() returns an int value I want to sent to a lineEdit in my GUI.
The main class looks like
class DPC: public QThread
{
Q_OBJECT
public:
void run();
signals:
void currentCount(int);
};
This code is called in the main function as:
DPC *newDPC = new DPC;
connect(newDPC, SIGNAL(currentCount(int)), SLOT(oncurrentCount(int)));
connect(newDPC, SIGNAL(finished()), newDPC, SLOT(deleteLater()));
newDPC->run();
How can I prevent this code from freezing my GUI? What am I doing wrong?
Thanks!

It seems that you code run in GUI thread because you use run() method to start thread, so try to call start() as documentation and many examples said.
Try:
DPC *newDPC = new DPC;
connect(newDPC, SIGNAL(currentCount(int)), SLOT(oncurrentCount(int)));
connect(newDPC, SIGNAL(finished()), newDPC, SLOT(deleteLater()));
newDPC->start();//not run
Anyways you can call thread() method or currentThread() to see in which thread some objects live.

Related

QLabel not updating image content [duplicate]

I work in Qt and when I press the button GO I need to continuously send packages to the network and modify the interface with the information I receive.
The problem is that I have a while(1) in the button so the button never finishes so the interface is never updated. I thought to create a thread in the button and put the while(){} code there.
My question is how can I modify the interface from the thread? (For example how can I modify a textBox from the thread ?
Important thing about Qt is that you must work with Qt GUI only from GUI thread, that is main thread.
That's why the proper way to do this is to notify main thread from worker, and the code in main thread will actually update text box, progress bar or something else.
The best way to do this, I think, is use QThread instead of posix thread, and use Qt signals for communicating between threads. This will be your worker, a replacer of thread_func:
class WorkerThread : public QThread {
void run() {
while(1) {
// ... hard work
// Now want to notify main thread:
emit progressChanged("Some info");
}
}
// Define signal:
signals:
void progressChanged(QString info);
};
In your widget, define a slot with same prototype as signal in .h:
class MyWidget : public QWidget {
// Your gui code
// Define slot:
public slots:
void onProgressChanged(QString info);
};
In .cpp implement this function:
void MyWidget::onProgressChanged(QString info) {
// Processing code
textBox->setText("Latest info: " + info);
}
Now in that place where you want to spawn a thread (on button click):
void MyWidget::startWorkInAThread() {
// Create an instance of your woker
WorkerThread *workerThread = new WorkerThread;
// Connect our signal and slot
connect(workerThread, SIGNAL(progressChanged(QString)),
SLOT(onProgressChanged(QString)));
// Setup callback for cleanup when it finishes
connect(workerThread, SIGNAL(finished()),
workerThread, SLOT(deleteLater()));
// Run, Forest, run!
workerThread->start(); // This invokes WorkerThread::run in a new thread
}
After you connect signal and slot, emiting slot with emit progressChanged(...) in worker thread will send message to main thread and main thread will call the slot that is connected to that signal, onProgressChanged here.
P.s. I haven't tested the code yet so feel free to suggest an edit if I'm wrong somewhere
So the mechanism is that you cannot modify widgets from inside of a thread otherwise the application will crash with errors like:
QObject::connect: Cannot queue arguments of type 'QTextBlock'
(Make sure 'QTextBlock' is registered using qRegisterMetaType().)
QObject::connect: Cannot queue arguments of type 'QTextCursor'
(Make sure 'QTextCursor' is registered using qRegisterMetaType().)
Segmentation fault
To get around this, you need to encapsulate the threaded work in a class, like:
class RunThread:public QThread{
Q_OBJECT
public:
void run();
signals:
void resultReady(QString Input);
};
Where run() contains all the work you want to do.
In your parent class you will have a calling function generating data and a QT widget updating function:
class DevTab:public QWidget{
public:
void ThreadedRunCommand();
void DisplayData(QString Input);
...
}
Then to call into the thread you'll connect some slots, this
void DevTab::ThreadedRunCommand(){
RunThread *workerThread = new RunThread();
connect(workerThread, &RunThread::resultReady, this, &DevTab::UpdateScreen);
connect(workerThread, &RunThread::finished, workerThread, &QObject::deleteLater);
workerThread->start();
}
The connection function takes 4 parameters, parameter 1 is cause class, parameter 2 is signal within that class. Parameter 3 is class of callback function, parameter 4 is callback function within the class.
Then you'd have a function in your child thread to generate data:
void RunThread::run(){
QString Output="Hello world";
while(1){
emit resultReady(Output);
sleep(5);
}
}
Then you'd have a callback in your parent function to update the widget:
void DevTab::UpdateScreen(QString Input){
DevTab::OutputLogs->append(Input);
}
Then when you run it, the widget in the parent will update each time the emit macro is called in the thread. If the connect functions are configured properly, it will automatically take the parameter emitted, and stash it into the input parameter of your callback function.
How this works:
We initialise the class
We setup the slots to handle what happens with the thread finishes and what to do with the "returned" aka emitted data because we can't return data from a thread in the usual way
we then we run the thread with a ->start() call (which is hard coded into QThread), and QT looks for the hard coded name .run() memberfunction in the class
Each time the emit resultReady macro is called in the child thread, it's stashed the QString data into some shared data area stuck in limbo between threads
QT detects that resultReady has triggered and it signals your function, UpdateScreen(QString ) to accept the QString emitted from run() as an actual function parameter in the parent thread.
This repeats every time the emit keyword is triggered.
Essentially the connect() functions are an interface between the child and parent threads so that data can travel back and forth.
Note: resultReady() does not need to be defined. Think of it as like a macro existing within QT internals.
you can use invokeMethod() or Signals and slots mechanism ,Basically there are lot of examples like how to emit a signal and how to receive that in a SLOT .But ,InvokeMethod seems interesting .
Below is example ,where it shows How to change the text of a label from a thread:
//file1.cpp
QObject *obj = NULL; //global
QLabel *label = new QLabel("test");
obj = label; //Keep this as global and assign this once in constructor.
Next in your WorkerThread you can do as below:
//file2.cpp (ie.,thread)
extern QObject *obj;
void workerThread::run()
{
for(int i = 0; i<10 ;i++
{
QMetaObject::invokeMethod(obj, "setText",
Q_ARG(QString,QString::number(i)));
}
emit finished();
}
you start thread passing some pointer to thread function (in posix the thread function have the signature void* (thread_func)(void*), something equal under windows too) - and you are completely free to send the pointer to your own data (struct or something) and use this from the thread function (casting pointer to proper type). well, memory management should be though out (so you neither leak memory nor use already freed memory from the thread), but this is a different issue

Signal from Main Thread not reaching slot in Second Thread Qt 5

I am writing a program that captures an Image from the Camera every REFRESH_RATE milliseconds to send it to some calculation algorithm. I decided to time the launch of this algorithm using a QThread, but the algorithm is running on the main thread, because I need objects created before in this one.
Anyway, this works well.
The trouble begins when I try to shut the second thread down... Here's the code.
Camera:
class Camera : public QMainWindow
{
Q_OBJECT
public:
Camera(QWidget *parent = 0){
AlgoQThread = new QThread;
myAlgoThreadWorker = new AlgoThreadWorker( (Camera *) this );
myAlgoThreadWorker->moveToThread(AlgoQThread);
//Launch The thread
connect(AlgoQThread, SIGNAL(started()), myAlgoThreadWorker, SLOT(process()));
connect(myAlgoThreadWorker, SIGNAL(finished()), AlgoQThread, SLOT(quit()));
// The line meant to stop the thread at next loop
connect(this, SIGNAL(stopAlgoThread()), myAlgoThreadWorker, SLOT(stopThread()));
connect(myAlgoThreadWorker, SIGNAL(finished()), myAlgoThreadWorker, SLOT(deleteLater()));
connect(AlgoQThread, SIGNAL(finished()), AlgoQThread, SLOT(deleteLater()));
AlgoQThread->start();
}
private slots:
void errorString(QString error);
//This function is triggered by a signal sent by the method called in AlgoThreadWoker::process()
void some_algorithm(){
...
emit stopAlgoThread();
}
signals:
void stopAlgoThread();
private:
QThread * AlgoQThread;
AlgoThreadWorker * myAlgoThreadWorker;
};
algoThreadWorker:
class AlgoThreadWorker : public QObject
{
Q_OBJECT
public:
AlgoThreadWorker(Camera * context){
parentCamera = context;
}
Camera* parentCamera;
public slots:
void process(){
while(1){
QMutexLocker locker(&m_mutex);
if (t_stop) break;
parentCamera->isCapturingImage = true;
//This triggers the some_algorithm() using a signal sent by imageCapture from main Thread
parentCamera->imageCapture->capture();
//Wait REFRESH_RATE millisecondes
Sleep(REFRESH_RATE);
}
//Ends the thread
emit finished();
}
private slots:
void stopThread(){
QMutexLocker locker(&m_mutex);
t_stop = true;
};
signals:
void finished();
void error(QString);
private:
bool t_stop;
QMutex m_mutex;
};
And well, as you may have foresee, it doesn't work. I can launch some_algorithm() with no problems but I can't end the thread. The stopThread() slot isn't even launched, I've tested that already.
Since you are busy waiting in your while loop, the event loop never gets a chance to process the received signals.
qApp->processEvents() gives the control to your event loop in order to process the awaiting jobs.
Note that generally you do not have to call it yourself, Qt does it for you. In your case, it is neccessary because you have an endless loop which prevents Qt from doing its job.
Solution :
void process(){
while(1){
qApp->processEvents();
^^^^^^^^^^^^^^^^^^^^^^
.....
}
//Ends the thread
emit finished();
}
stopThread() is private and thus only accessible from AlgoThreadWorker.
Qt's event loop already provides for safe cross-thread slot call and event delivery. Your mistakes are mostly to do with incorrectly reimplementing what Qt already provides:
Things are already thread-safe. Drop the mutex.
thread->quit() works and will exit from the event loop running in the given thread. In a QThread, the thread will then finish,.
Don't make your code non-portable for no reason (Sleep is Windows-specific). If you wish do things periodically, simply run a timer (QBasicTimer or QTimer).
This answer provides a complete example.

Issues with Qt's signals and slots behavior with multithreading

I'm currently trying to understand how signals and slots in Qt behave with threads.
I've tried to run a small test with the following code:
class Worker : public QObject{
Q_OBJECT
public:
Worker(int _value){value = _value;}
~Worker(){};
int value;
public slots:
void changeValue(int newValue){value = newValue;}
void doWork(){
while(1){
_sleep(500);
std::cout << "Value is " << value << std::endl;
if(value == 0)break;
}
emit finished();
}
signals:
void finished();
};
class Manager : public QObject{
Q_OBJECT
public:
Manager(){}
~Manager(){};
signals:
void modifiedValue(int value);
public:
void changeTheValue(int value){emit modifiedValue(value);}
};
Basically, the worker display its value member every once in a while, and has a slot with a function that modifies the value.
The manager has the only purpose of emitting a signal with a new value when changeTheValue is called, that maps to the slot in Worker that modifies the value member.
Then I make my Worker class work in a thread the following way :
QThread myThread;
Worker myWorker(10);
Manager manager;
myWorker.moveToThread(&myThread);
QObject::connect(&myThread, SIGNAL(started()), &myWorker,SLOT(doWork()));
QObject::connect(&myWorker, SIGNAL(finished()), &myThread, SLOT(quit()));
QObject::connect(&myWorker, SIGNAL(finished()), &myWorker, SLOT(deleteLater()));
QObject::connect(&myThread, SIGNAL(finished()), &myThread, SLOT(deleteLater()));
QObject::connect(&manager, SIGNAL(modifiedValue(int)),
&myWorker, SLOT(changeValue(int)));
myThread.start();
for(int i = 1; i < 10 ; i++){
_sleep(1000);
manager.changeTheValue(i);
}
manager.changeTheValue(0);
But nothing happens. The value doesn't seem to be changed: output show a dozen lines with Value is 10.
What I can't understand is, why does the signal/slot mapping with Manager::modifiedValue and Worker::changeValue does not seem to work ? Is it only because the thread is currently running the doWork()'s loop ? Where does the call to the slots ends up then (queued, discarded, other) ?
I couldn't find much more on how does the signals/slots mechanism work with threads (I only found this thread which explains in which thread's call stack does the call to the slot end up, but the link provided in the answer seems outdated and leads to Qt 5 home).
To sum up the questions:
Why does the call to the slot that modifies the value does nothing ?
Is it possible to make this work (adding thread-safety wherever necessary) and how ?
There are multiple modes of how signals and slots work with threads (you absolutely must use QThreads for these to work!). These are documented in the manual:
http://qt-project.org/doc/qt-4.8/threads-qobject.html#signals-and-slots-across-threads
The mistake in your code is that the Qt event loop is never called (as doWork never returns). For a repeating call you should be using a timer in that thread. Alternatively (NOT the recommended solution) you can call processEvents in your infinite loop.

QT threads :Getting QObject::startTimer: timers cannot be started from another thread warning

I follow the examples from the Qt SDK, starting timer in the QThread Subclass
but I keep getting the warning and the thread never starts the timer.
Here is the code:
NotificationThread::NotificationThread(QObject *parent)
:QThread(parent),
m_timerInterval(0)
{
moveToThread(this);
}
NotificationThread::~NotificationThread()
{
;
}
void NotificationThread::fire()
{
WRITELOG("A::fire called -- currentThread:" + QString::number((int)currentThread()->currentThreadId()));
QVector<StringPer>* batchVectorResult = new QVector<StringPer>();
emit UpdateGroupNotifications(batchVectorResult);
}
void NotificationThread::run()
{
connect(&m_NotificationTimer, SIGNAL(timeout()),
this,SLOT(fire(),Qt::DirectConnection));
WRITELOG("A::run() worker thread -- currentThread:" + QString::number((int)currentThread()->currentThreadId()));
//SetNotificationTimerFromConf();
QVariant val(ConfigSettings::getInstance()->ReadFromSettingsReturnVariant(SETTINGS_KEY_NOTIFICATIONTHREAD));
int interval = val.toInt();
m_NotificationTimer.setInterval(interval);
m_NotificationTimer.start();
QThread::exec();
}
void NotificationThread::SetNotificationTimerFromConf()
{
QVariant val(ConfigSettings::getInstance()->ReadFromSettingsReturnVariant(SETTINGS_KEY_NOTIFICATIONTHREAD));
int interval = val.toInt();
m_NotificationTimer.setInterval(interval);
}
void NotificationThread::UpdateNotificationTimerRT(int timerInterval)
{
m_NotificationTimer.setInterval(m_timerInterval);
}
void NotificationThread::Execute(const QStringList batchReqList)
{
QVector<QString>* batchVectorResult = new QVector<QString>();
start();
}
I start the Thread from the main GUI with Execute( ).
The problem is that you create the timer implicitly by the main thread when you create your thread object. This is because your timer is a member of your thread class.
When you try to start the timer, you do in a different thread (in run()), not in the thread where the timer was created, which gives you the warning.
You need to create the timer in the thread where you want to run it:. Change the declaration of m_notificationTimer in your NotificcationThread class from
QTimer m_NotificationTimer;
to
QTimer* m_NotificationTimer;
and create the timer in run() with
m_NotificationTimer = new QTimer(this);
m_NotificationTimer->setInterval(interval);
m_NotificationTimer->start();
If you add the line
m_NotificationTimer.moveToThread(this);
to beginning of run() method of your thread from that point on your timer object will invoke the connected slot within the your thread.
When you first create the timer it will run within your main thread. By moving it to your own thread as above the moveToThread method will change the thread affinity of the timer object.
It is also worth mentioning this article
The biggest adjustment for me was to understand that threads in qt are used as an interface, and are not really intended for subclassing. With that being said, I would keep your class and and actual QThread separate. And then just use YourClass.moveToThread( &YourQtThread) to ensure your signals and slots are process on that thread.

Is it possible to implement polling with QThread without subclassing it?

I have a class, which is an abstraction of some device.
class Device
{
public:
...
void Start();
void Stop();
void MsgLoop();
signals:
void sMsgArrived();
}
Start() and Stop() are called from GUI thread. Start() begins new thread, which runs MsgLoop(). It looks like this:
void MsgLoop()
{
forever {
if(SUCCESS == ReadMsg()) //synchronous, non-blocking
{
ProcessMsg(); //quite fast
emit sMsgArrived(); //this signal is connected with a slot in GUI thread
}
}
}
When Stop() is called, program should return from MsgLoop() and stop the thread. How can I implement this with QThread without subclassing it?
Generally you have to decide who will be responsible for managing the thread. Is it the Device or the main window? Or possibly some device manager. In your case the Device should probably manage its own thread, so if you don't want to subclass it, use composition:
class Device : QObject
{
Q_OBJECT
public:
Device(QObject * parent = NULL);
void Start();
void Stop();
private slots:
void MsgLoop();
signals:
void sMsgArrived();
private:
QThread thread;
bool stopThread;
};
Device::Device(QObject * parent) : QObject(parent)
{
moveToThread(&thread);
connect(&thread, SIGNAL(started()), this, SLOT(MsgLoop()));
}
void Device::Start()
{
stopThread = false;
thread.start();
}
void Device::Stop()
{
stopThread = true;
thread.wait(); // if you want synchronous stop
}
void Device::MsgLoop()
{
// your loop
while(!stopThread)
if(SUCCESS == ReadMsg())
{
ProcessMsg();
emit sMsgArrived();
}
QThread::currentThread->quit();
}
NOTE: the thread stopping will only work if ReadMsg really is non-blocking. If you later decide to switch to blocking read (and that would probably be appropriate for most cases), you will have to figure out another way how to stop your thread.
If you look at this link you can see that it is possible to run a method in a separate thread without subclassing a QThread.
However what you are asking is running a message loop forever.
If you follow the given example you can run your loop without subclassing but the QThread object will never enter into its own message loop cause it will never return from your slot. So here is an example but I think it would be a bad design
class Device : public QObject
{
Q_OBJECT
public:
Device(QObject* parent = 0);
~Device();
public Q_SLOTS:
void MsgLoop();
};
QThread* thread = new QThread;
Device* device = new Device;
void Widget::onBtnStartClicked()
{
device->moveToThread(thread);
//This will call start method of Device
connect(thread, SIGNAL(started()), device, SLOT(MsgLoop()));
//This will start the event loop of thread
thread->start();
}
void Widget::onBtnStopClicked()
{
//Tells the thread to exit
thread->exit(0);
}
I am afraid you have to subclass a QThread if you want to run a forever loop.
IMHO you shouldn't. Polling requires being in a forever loop. You must do this in QThread's run function so there is no way to re-implement a function without sub-classing first. Even if you were to try and workaround it with a single shot timer I don't recommend it. You are better off(this is how i like to do it) sub-classing QThread, calling moveToThread(), not call exec() and put a forever loop in run. For an example of this look at the Fortune Blocking Client example from qt. If you don't call moveToThread() on QThread then the QThread object still resides in the GUI main thread and they both share the same event loop (which is bad when using polling functions). Calling moveToThread(QThread) without calling exec() means the QThread will not have an event loop(which is good in your case). Calling exec() would start it's own event loop but is not used for polling schemes and you would leave the run function.