emit SIGNAL when GUI Thread is idle in Qt? - c++

I have GUI Thread which creates & manages the GUI content. Now when the application is idle i.e. all threads are idle (or even if only the GUI thread is idle) then I want my QMainWindow inherited class's object to emit a SIGNAL. So that whenever the Application is idle I will silently create the Widgets required for the next stage. So I would like to know how do I make that object to emit a SIGNAL whenever the GUI Thread is idle? My Application is multi-threaded & has multiple classes, so it is not necessary that the SIGNAL is emitted in the GUI class only.
Also the SIGNAL should not be emitted as soon as the thread becomes idle. I want that the thread should be idle for a sufficient amount of time so that I am sure that the user is actually idling.
Thank You!

QAbstractEventDispatcher allows one to plug their own events into Qt's event loop. Also it allows to monitor event loop's workload.
Here is an example. The widget is listening for QAbstractEventDispatcher::awake() and QAbstractEventDispatcher::aboutToBlock() signals to know when event loop is busy.
#include <QtGui>
class IdleAwareWidget : public QWidget
{
Q_OBJECT
public:
IdleAwareWidget(QWidget *parent = 0) : QWidget(parent) {
dispatcher = QAbstractEventDispatcher::instance();
connect(dispatcher, SIGNAL(awake()), SLOT(awake()));
connect(dispatcher, SIGNAL(aboutToBlock()), SLOT(aboutToBlock()));
}
private slots:
void awake() {
lastAwake = QTime::currentTime();
qDebug() << "Slept for " << lastBlock.msecsTo(lastAwake) << " msec";
}
void aboutToBlock() {
lastBlock = QTime::currentTime();
qDebug() << "Worked for " << lastAwake.msecsTo(lastBlock) << " msec";
}
private:
QAbstractEventDispatcher *dispatcher;
QTime lastAwake;
QTime lastBlock;
};
main.cpp:
#include <QtGui>
#include "idle_widget.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
IdleWidget widget;
widget.show();
return a.exec();
}
If the question is just about idle processing, then QTimer with 0 interval is an option:
QTimer::singleShot(0, this, SLOT(doWorkInIdle()));
This will schedule call to doWorkInIdle() slot as soon as the event loop goes to idle state. Splitting work to small chucks won't block the loop and application will remain responsive.

Related

Why can't I start a QThread on a signal?

I want to start a QThread when another one starts, but it doesn't work.
main.cpp snippet
Worker stat_worker;
stat_worker.moveToThread(stat_worker.stat_thread);
Worker some;
some.moveToThread(some.somethread);
QObject::connect(stat_worker.stat_thread, SIGNAL(started()), some.somethread, SLOT(start()));
QObject::connect(some.somethread, SIGNAL(started()), &some, SLOT(print_some()));
stat_worker.stat_thread->start();
worker.h
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker();
QThread *stat_thread = new QThread;
QThread *somethread = new QThread;
signals:
//some signals
void start_thread();
public slots:
//some slots
void print_some();
void somethread_starter();
};
#endif // WORKER_H
worker.cpp related function
void Worker::print_some()
{
qInfo() << "-somethread started() signal arrived!";
}
When I tried starting a thread with clicking a pushbutton it didn't work either.
Even creating a slot which starts the thread:
QObject::connect(stat_worker.stat_thread, &QThread::started, &some, &Worker::somethread_starter);
void Worker::somethread_starter()
{
qInfo() << "-I got started by another thread!";
somethread->start();
}
or a signal that is emitted on starting the other thread:
void Worker::wip_status(){
emit start_thread();
}
QObject::connect(stat_worker.stat_thread, &QThread::started, &stat_worker, &Worker::wip_status);
QObject::connect(&stat_worker, &Worker::start_thread, &some, &Worker::somethread_starter);
work.
Thanks in advance for replying to my post.
I tried to reproduce OPs issue with my own MCVE (which is just a bit shorter).
#include <QtWidgets>
struct Worker: QObject {
QString name;
QThread qThread;
Worker(const QString &name): name(name)
{
moveToThread(&qThread);
connect(&qThread, &QThread::finished, this, &Worker::reportFinished);
}
void start()
{
qDebug() << "Start" << name;
qThread.start();
}
void reportFinished()
{
qDebug() << "Exit" << name;
}
};
// main application
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QCoreApplication app(argc, argv);
Worker worker1("worker 1");
Worker worker2("worker 2");
// install signal handlers
QObject::connect(&worker1.qThread, &QThread::started, &worker2, &Worker::start);
worker1.start();
// runtime loop
return app.exec();
}
Output:
Qt Version: 5.13.0
Start "worker 1"
This what OP observed. So, what?
the worker1.qThread.started signal is connected to the worker2.start slot
the worker1 is started
worker2 doesn't seem to start.
What made me suspicious: moveToThread().
The intention is to associate the Worker object with its member QThread.
What I'm not sure about: Is this possible before the QThread is started?
To check this out, I commented the moveToThread():
Worker(const QString &name): name(name)
{
//moveToThread(&qThread);
connect(&qThread, &QThread::finished, this, &Worker::reportFinished);
}
Output:
Qt Version: 5.13.0
Start "worker 1"
Start "worker 2"
The reason why I commented the moveToThread():
The call of qThread::start() should happen in the context of the main application (thread).
So, moving worker2 to its QThread means that the signal is sent to the event loop of worker2.qThread – which is actually not yet started.
Hence, the event cannot be processed.
The moveToThread() should be done later – e.g. in reaction of the started() signal:
#include <QtWidgets>
struct Worker: QObject {
QString name;
QThread qThread;
Worker(const QString &name): name(name)
{
connect(&qThread, &QThread::started, this, &Worker::moveThisToThread);
connect(&qThread, &QThread::finished, this, &Worker::reportFinished);
}
void start()
{
qDebug() << "Start" << name;
qThread.start();
}
void moveThisToThread()
{
moveToThread(&qThread);
qDebug() << name << "associated to its thread, from now.";
}
void reportFinished()
{
qDebug() << "Exit" << name;
}
};
// main application
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QCoreApplication app(argc, argv);
Worker worker1("worker 1");
Worker worker2("worker 2");
// install signal handlers
QObject::connect(&worker1.qThread, &QThread::started, &worker2, &Worker::start);
worker1.start();
// runtime loop
return app.exec();
}
Output:
Qt Version: 5.13.0
Start "worker 1"
"worker 1" associated to its thread, from now.
Start "worker 2"
"worker 2" associated to its thread, from now.
Bonus Question:
So does that mean "QThread::start" is useless as receiver of a signal?
No, it's not. Even if there is no existing signal with that signature (I know about) the application developer is free to “invent” one.
However, remembering that Qt5 doesn't actually require explicitly marked SLOTs to use them for signals, a more obvious answer may be found in the past:
With Qt4 signals, the QThread::start slot could have been connected to the QThread::started signal directly. (The default value of the one and only parameter in QThread::start becomes effective then.)
As I have no experience with Qt4 signals (I started with Qt5), I modified my sample code to prove me right:
QObject::connect(&worker1.qThread, SIGNAL(started()), &worker2.qThread, SLOT(start()));
Output:
Qt Version: 5.13.0
Start "worker 1"
"worker 1" associated to its thread, from now.
"worker 2" associated to its thread, from now.
The Start "worker 2" isn't emitted anymore as worker1.started() calls worker2.qThread.start() directly, now.
So, with Qt4 signals the original code of OP might have been worked.
It wasn't the incompatibility of signal and slot (as somebody guessed) which caused the issue but probably the above described moveToThread() issue (as well) which didn't make it work satisfyingly.

How to close the programme when running a qtconcurrent from another thread in qt

I am running a programme that has multithreading . The programme firstly has a main / UI thread running in it. In this programme I have a worker and handler class.
The worker class is having a simulate function which simply generates the random number. The simulate function continuously generates the number without blocking any thread i.e. via Qtconcurrent.
From the main/UI thread I have put this worker class into new thread. The handler class is running in main /UI thread and is responsible to communicate with worker class running in other thread via signal slot.
So far everything is ok.
Problem starts when i try to close the programme by simply clicking on app cross button. The
programme sort of hangs it does not close. However when i dont put worker in another class and run worker class from same main /UI thread then there is no problem and programme exits with 0.
So my question is how to stop Qtconcurrent is another thread and finally close the another thread aswell.
Thank You.
main.cpp
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
QThread l_newThread;
Worker* l_worker = new Worker();
handler * l_handler = new handler();
l_worker->moveToThread(&l_newThread);
QObject::connect(&l_newThread, &QThread::started, l_worker, &Worker::Init);
QObject::connect(l_handler,&handler::toStop_Signal,&l_newThread, &QThread::quit);
QObject::connect(l_worker, &Worker::toStop_Signal_Worker, l_handler,&handler::toStop_Slot);
QObject::connect(&app,&QCoreApplication::aboutToQuit, l_worker, &Worker::stop);
// QObject::connect(&app,&QCoreApplication::aboutToQuit, &l_newThread, &QThread::quit);
l_newThread.start();
// l_worker->Init();
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
int result = app.exec();
l_newThread.wait();
return result;
}
worker.cpp
#include "worker.h"
Worker::Worker(QObject *parent) : QObject(parent)
{
}
void Worker:: Init()
{
m_simulation = true;
simulate();
}
void Worker::simulate()
{
QtConcurrent::run([this]{
QRandomGenerator generator;
while (m_simulation) {
qint32 t = generator.bounded(0,100);
qDebug() << t;
qDebug() << "sleeping for 1 second";
QThread::sleep(1);
}
if (!m_simulation) {
qDebug() << "Killing the concurrent thread";
// QThread::currentThread()->exit();
emit toStop_Signal_Worker();
}
});
}
void Worker::stop()
{
m_simulation = false;
}
handler.cpp
#include "handler.h"
handler::handler(QObject *parent) : QObject(parent)
{
}
void handler::toStop_Slot()
{
emit toStop_Signal();
}
results
QML debugging is enabled. Only use this in a safe environment.
19
sleeping for 1 second
55
sleeping for 1 second
70
sleeping for 1 second
69
sleeping for 1 second
Killing the concurrent thread
What probably happens here: the signal toStop_Signal which is meant to quit l_newThread is never delivered, because when it's emitted the event loop is already dead and gone. Hence, your program is stuck waiting for the thread in l_newThread.wait();.
I don't fully get why you start this thread at all, just to use QtConcurrent::run right after and span yet another thread ...
Anyway, once you're sure your worker has stopped (and you are, according to the output you posted), you can safely quit the (basically useless) thread directly in your main:
int result = app.exec();
l_newThread.exit(); //just quit it
l_newThread.wait();
return result;
Then you can get rid of this connection:
QObject::connect(l_handler,&handler::toStop_Signal,&l_newThread, &QThread::quit);
and (I guess) of the handler altogether.

qt serial port memory leak

I use the following code to talk to a USB-serial port device:
#include "masterthread.h"
#include <QtSerialPort/QSerialPort>
#include <QTime>
#include "Windows.h"
#include "Psapi.h"
#include <QDebug>
QT_USE_NAMESPACE
MasterThread::MasterThread(QObject *parent)
: QThread(parent), waitTimeout(0), quit(false)
{
}
MasterThread::~MasterThread()
{
mutex.lock();
quit = true;
cond.wakeOne();
mutex.unlock();
wait();
}
void MasterThread::run()
{
bool currentPortNameChanged = false;
QSerialPort serial;
serial.setPortName("COM3");
serial.setBaudRate(57600);
serial.setStopBits(static_cast<QSerialPort::StopBits>(1));
serial.setDataBits(static_cast<QSerialPort::DataBits>(8));
serial.setParity(static_cast<QSerialPort::Parity>(0));
serial.open(QIODevice::ReadWrite);
//Tell the serial port connected device to start talking
//--------------------------------------
const char init[] = { 0x0d, 0x0d, 0x0d };
serial.write(init, sizeof(init));
const char* cmd = "mavlink stop\n";
serial.write(cmd, strlen(cmd));
serial.write(init, 2);
cmd = "uorb start";
serial.write(cmd, strlen(cmd));
serial.write(init, 2);
cmd = "sh /etc/init.d/rc.usb\n";
serial.write(cmd, strlen(cmd));
serial.write(init, 4);
serial.waitForBytesWritten(100);
int i = 0;
int j = 0;
forever
{
//Write test data out
//-----------------------------
QByteArray test(2000, 't');
serial.write(test);
bool check = serial.waitForBytesWritten(100);
if (!check)
{
qDebug() << "FAIL: " << j++;
}
if (serial.waitForReadyRead(20))
{
QByteArray responseData = serial.readAll();
while (serial.waitForReadyRead(10))
responseData += serial.readAll();
QString response(responseData);
qDebug() << response;
}
QThread::msleep(20);
//Print memory usage
//---------------------------------------------------
if (i++ % 10 == 0)
{
PROCESS_MEMORY_COUNTERS memcount;
if (!GetProcessMemoryInfo(GetCurrentProcess(), &memcount, sizeof(memcount))) return;
qDebug()<<"----------------------------" << memcount.WorkingSetSize / 1024 << "KB memory used";
}
} // end foever
qDebug() << "Exiting forever loop";
}
with a simple main.cpp as:
#include <QApplication>
#include "masterthread.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MasterThread thread;
thread.start();
return app.exec();
}
But the memory usage keeps increasing, like 5~10MB per hour as if there are some leakage.
The device is suppose to be connected for days and weeks...
What am I doing wrong here? I am on Qt5.6 windows7 debug
Many Qt Components have an implicit dependency on its event loop.
While you are starting the main threads event loop with the call to app.exec(); you are not handling events generated by the QObjects created in the QThread MasterThread thread;. The details and nuances of Event handling in Qt are very well described on this page: https://wiki.qt.io/Threads_Events_QObjects#Threads_and_QObjects
But the solution boils down to: if you want to be able to process queued up Qt events in a thread where you are processing some long-running task you should call QCoreApplication::processEvents(); from time to time. This will prevent Qt events from endlessly queueing up.
EDITED after looking on the code Qt 5.7,5.6,5.5 and reading docs.
As an answer is already accepted, I would just add some thoughts here as it's too long for comments.
Keep things short - an answer you accepted is wrong..
There are two sides of the story. And as SO answers often taken 'as it is as long as they work' I'd like to explain myself...
If you look on a code provided - there is nothing wrong with it. All objects are properly stack allocated and should be destroyed automatically.
Point is that QtSerial uses deleteLater() and then a question - how to delete those allocations properly.
If any module/object/code uses deleteLater() it requires an event loop, if deleteLater() called on a thread without event loop, object will be deleted after thread is terminated. As long as there is no event loop running for code above, processEvents will no work.. actually processEvents() is not something which is used for this, because a whole idea to return from the context which is called deleteLater() and have a next run, and that's checked in the Qt Source Code, so calling processEvent() straight after without incrementing loop count will do nothing at all, that's why answer you accepted is totally wrong.
Conclusion:
If any object requires event loop running it should be EXPLICITELY stated in the documentation as there is nothing wrong in using QIODevice in sync mode outside event loop.
So at my opinion,point is - its a bug in the QT Serial itself which I suggest you report.
In general it's really wrong practice for Qt to run never-ending loops..
It's much much better and cleaner to use QObject Worker tactic which is pushed to the thread, have proper even loop running etc.
For small 'threaded' tasks it's much better to use QtConcurrent.
Proper Workaround:
you will have a thread with properly running event loop and a timer firing at 20ms to do your things
// main thread:
class Worker: public QObject {
public:
Worker();
public slots:
onInit() {
// initialize everything
startTimer(20);
}
protected:
void timerEvent(..) {
// do your things every 20ms
}
}
...
QThread * pWorkerThread = new QThread();
pWorkerThread->setObjectName(QString("Serial"));
Worker * pWorker = new Worker();
Worker->setObjectName(QString("Common Storage Impl"));
Worker->moveToThread(WorkerThread);
connect(pWorkerThread, SIGNAL(started()), pWorker, SLOT(onInit()));
connect(pWorkerThread, SIGNAL(finished()), pWorker, SLOT(deleteLater()));
connect(pWorkerThread, SIGNAL(finished()), pWorkerThread, SLOT(deleteLater()));
pWorkerThread->start();
...

Wait for signal while processing other signals

My Qt application talks to a serial device, and occasionally has to wait for this device to send a byte. To accomplish this, I create a new eventloop that exits as soon as there is information available in the serial buffer:
unsigned char MyClass::waitForDevice(int timeout)
{
QEventLoop wait;
connect(d_serial, SIGNAL(readyRead()), &wait, SLOT(quit()));
if (timeout > 0)
QTimer::singleShot(timeout, &wait, SLOT(quit()));
wait.exec();
return static_cast<unsigned char>(d_serial->read(1)[0]);
}
Now the problem is that, while the application is waiting, i.e. while the eventloop is running, I need to be able to communicate to the serial device when a button is pressed in the GUI. Naively, I tried connecting a signal to a slot that does this, but I found that the slot is only executed after the eventloop is terminated.
I tried, without any luck, to have a seperate QThread running that calls qApp->processEvents() in an infinite loop, which is terminated when the eventloop is terminated. This didn't work, and I'm not quite sure why not. What is the canonical way to resolve this?
You're thinking synchronously in a pre-C++1z world. In C++14 (and prior) asynchronous programming, there is mostly no place for a notion of a wait that is implemented as a function that returns when the wait is over (switch-based coroutine hacks excepted). You are also not using the fact that your application is stateful, and the state transitions can be expressed in a state machine.
Instead, you should simply act on data being available. Presumably, your application can be in multiple states. One of the states - the one where you have to wait for input - is simply exited when the input arrives.
The example below uses a simple process-local pipe, but it would work exactly the same if you were using a serial port - both are a QIODevice and emit requisite signals. We start with the project file.
# async-comms-32309737.pro
QT += widgets core-private
TARGET = async-comms-32309737
CONFIG += c++11
TEMPLATE = app
SOURCES += main.cpp
To make things simple, the pipe implementation reuses the QRingBuffer private class from Qt. See this question for more fleshed-out implementation(s).
// main.cpp
#include <QtWidgets>
#include <private/qringbuffer_p.h>
/// A simple point-to-point intra-application pipe. This class is not thread-safe.
class AppPipe : public QIODevice {
Q_OBJECT
AppPipe * m_other { nullptr };
QRingBuffer m_buf;
public:
AppPipe(AppPipe * other, QObject * parent = 0) : QIODevice(parent), m_other(other) {
open(QIODevice::ReadWrite);
}
void setOther(AppPipe * other) { m_other = other; }
qint64 writeData(const char * data, qint64 maxSize) Q_DECL_OVERRIDE {
if (!maxSize) return maxSize;
m_other->m_buf.append(QByteArray(data, maxSize));
emit m_other->readyRead();
return maxSize;
}
qint64 readData(char * data, qint64 maxLength) Q_DECL_OVERRIDE {
return m_buf.read(data, maxLength);
}
qint64 bytesAvailable() const Q_DECL_OVERRIDE {
return m_buf.size() + QIODevice::bytesAvailable();
}
bool isSequential() const Q_DECL_OVERRIDE { return true; }
};
We start with a simple UI, with one button to restart the state machine, another to transmit a single byte that will be received by the client, and a label that indicates the current state of the state machine.
int main(int argc, char *argv[])
{
QApplication a { argc, argv };
QWidget ui;
QGridLayout grid { &ui };
QLabel state;
QPushButton restart { "Restart" }, transmit { "Transmit" };
grid.addWidget(&state, 0, 0, 1, 2);
grid.addWidget(&restart, 1, 0);
grid.addWidget(&transmit, 1, 1);
ui.show();
We now create the simulated device and the client pipe endpoints.
AppPipe device { nullptr };
AppPipe client { &device };
device.setOther(&client);
The state machine has three states. The s_init is the initial state, and is exited after a 1.5s delay. The s_wait state is only exited when we receive some data (a byte or more) from the device in that state. In this example, receiving the data in other states has no effect. The machine is set to restart automatically when stopped.
QStateMachine sm;
QState
s_init { &sm }, // Exited after a delay
s_wait { &sm }, // Waits for data to arrive
s_end { &sm }; // Final state
QTimer timer;
timer.setSingleShot(true);
sm.setInitialState(&s_init);
QObject::connect(&sm, &QStateMachine::stopped, &sm, &QStateMachine::start);
QObject::connect(&s_init, &QState::entered, [&]{ timer.start(1500); });
s_init.addTransition(&timer, SIGNAL(timeout()), &s_wait);
s_wait.addTransition(&client, SIGNAL(readyRead()), &s_end);
To visualize the state machine's progress, we assign the state label's text property in each of the states:
s_init.assignProperty(&state, "text", "Waiting for timeout.");
s_wait.assignProperty(&state, "text", "Waiting for data.");
s_end.assignProperty(&state, "text", "Done.");
Finally, the restart button stops the state machine - it will self-restart then. The transmit button simulates the device sending one byte of data.
QObject::connect(&restart, &QPushButton::clicked, &sm, &QStateMachine::stop);
QObject::connect(&transmit, &QPushButton::clicked, [&]{
device.write("*", 1);
});
We start the machine, enter the event loop, and let Qt follow our directions onwards from here. The main.moc file is included for it contains the metadata for AppPipe.
sm.start();
return a.exec();
}
#include "main.moc"
There are several Types of which Signals and Slots can be connected.
See: http://doc.qt.io/qt-4.8/qt.html#ConnectionType-enum
Have you tried Qt::DirectConnection: connect(d_serial, SIGNAL(readyRead()), &wait, SLOT(quit()),Qt::DirectConnection); ?

QObject::moveToThread: Widgets cannot be moved to a new thread

My IDE Qt 5.0.1, platform Linux
i have a problem about set widgets to window.(My opinion)
this is my main.cpp->
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QThread cThread;
MainWindow w;
w.doSetup(cThread);
w.moveToThread(&cThread);
cThread.start();
if(cThread.isRunning())
{
qDebug() << " Thread is Running...";
}
w.show();
return a.exec();
}
this is doSetup() method->
void MainWindow::doSetup(QThread &mainThread)
{
QObject::connect(&mainThread, &QThread::started, this, &MainWindow::activeLoopMainC);
}
i checked my signal-slot mechanism and it works.
slot method->
void MainWindow::activeLoopMainC()
{
qDebug() << " Signal-Slot structure working successfully..";
mainThreadProc((void*)(instAddr));
}
i call a function from my main.c by this slot method.
In debugging there is no problem about working codes. But my window is blank. there is only frame.
i receive an error message: QObject::moveToThread: Widgets cannot be moved to a new thread
How can i solve this problem?
Thank you in advance for your answers.
You can't move widgets into another thread - in order to keep user interface responsive, Qt needs to do all GUI work inside main thread.
If you have background work to do, then move background worker to other thread, and not the user interface.