I'm trying to understand and use RAII and wanted opinions on this implementation:
I want the RAII PauseProcessRAII to emit a signal and another one in the destructor. Example:
// Header
public:
PauseProcessRAII(QObject *parent = 0);
void Execute();
~PauseProcessRAII();
signals:
void PauseProcess(bool pause_process);
// Source
PauseProcessRAII::~PauseProcessRAII()
{
emit PauseProcess(false);
}
void PauseProcessRAII::Execute()
{
emit PauseProcess(true);
}
// MainWindow code
void MainWindow::OnPauseProcessRAII(bool pause_process)
{
qDebug() << "pause_process: " << pause_process;
}
void MainWindow::OnButtonSaveClicked()
{
PauseProcessRAII pauseProcessRAII(this);
connect(&pauseProcessRAII, &PauseProcessRAII::PauseProcess, this, &MainWindow::OnPauseProcess);
pauseProcessRAII.Execute();
// ... Some code runs
// ... pauseRAII desctructor is called
}
When I run the code both emits are firing as expected. My question is this a good solution? At first I though the emit call in PauseProcessRAII destructor wouldn't have worked because it may have destroyed the signal and slot connection. Of course that would mean I would have to add the connect to every function that I use it on.
The whole idea is fundamentally broken if your premise is that the code indicated by "Some code runs" runs long enough to block the GUI. If so: don't do that. The only code that is supposed to ever execute in the GUI thread is short, run-to-completion code that doesn't take long enough for the user to notice.
If the time taken by "Some code runs" is very short - on the order of single milliseconds at most - then you can certainly use such a construct. The term RAII doesn't apply here, as you're dealing with some sort of a scope guard.
If you wish, you can forgo the execute method and perform the connection in the constructor:
// https://github.com/KubaO/stackoverflown/tree/master/questions/scopeguard-signal-34910879
// main.cpp
#include <QtCore>
class ScopeSignaller : public QObject {
Q_OBJECT
public:
Q_SIGNAL void inScope(bool);
template <typename F>
ScopeSignaller(QObject * target, F && slot, QObject * parent = 0) : QObject(parent) {
connect(this, &ScopeSignaller::inScope, target, std::forward<F>(slot));
inScope(true);
}
~ScopeSignaller() {
inScope(false);
}
};
int main(int argc, char ** argv) {
QCoreApplication app{argc, argv};
ScopeSignaller s(&app, +[](bool b){ qDebug() << "signalled" << b; });
}
#include "main.moc"
Related
I am trying to perform multiple long-running initializers on threads. I would like to get results as soon as they are available, regardless of order.
I have tried with a simple thread but got stuck where I needed to create multiple threads... and manage them... And the idea of thread pool, futures, thread watcher kept coming up in my research. So, this is my latest try:
struct Initializers {
BigObject *newBigObject;
bool newValue;
int initValue;
};
class BigObject {
public:
BigObject(QString) {}
void initialize(bool, int) {}
};
class MyClass : public QObject {
Q_OBJECT
public:
MyClass() {
connect(&m_futureWatcher, SIGNAL(resultReadyAt(int)), this, SLOT(initUsingFutureSlot(int)));
connect(&m_futureWatcher, SIGNAL(finished()), this, SLOT(initUsingFutureSlot()));
}
void doImportantWork(QStringList someNames);
private slots:
void initUsingFutureSlot(int);
void initUsingFutureSlot();
private:
void createThreadConnections();
//void initComplete(BigObject *);
QFutureWatcher<void> m_futureWatcher;
QVector<Initializers> m_initializersVector;
};
void longInitializer(Initializers &initializers) {
qDebug() << "Running in thread" << QThread::currentThreadId();
initializers.newBigObject->initialize(initializers.newValue, initializers.initValue);
}
void MyClass::doImportantWork(QStringList someNames) {
qDebug() << QString("Long running process using %1 thread(s)").arg(QThread::idealThreadCount());
// Prepare the vector.
foreach (QString someName, someNames) {
BigObject *newBigObject = new BigObject(someName);
Initializers initializers;
initializers.newBigObject = newBigObject;
initializers.newValue = m_appValue;
initializers.initValue = m_appInit;
m_initializersVector.append(initializers);
}
// Start the work
m_futureWatcher.setFuture(QtConcurrent::map(m_initializersVector, longInitializer));
//m_futureWatcher.waitForFinished();
}
// This does not get called
void MyClass::initUsingFutureSlot(int index) {
qDebug() << "Finished" << index;
//initComplete(m_initializersVector.at(index).newBigObject);
}
// This does not get called
void MyClass::initUsingFutureSlot() {
qDebug() << "Finished"
}
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
MyClass task;
task.doImportantWork(QStringList() << "Hello" << "World");
return app.exec();
}
This version of my code is based on QT5 Tutorial QProgressDialog with QtConcurrent which is the only complete example I was able to find that works with multiple threads.
One problem - their QFutureWatcher's type is void - and I could not find any way to modify the code to use a different type - and not give compile errors. That is why I made the vector they use a class member, to grab the values from there.
My understanding is that the vector gets the slot applied to every member of it - based on documentation.
So, I ran it, but nothing happens. The debug message shows that the threads are running. But the resultReadyAt or finished and their corresponding slots are not called. In addition, closing the program says QThread: Destroyed while thread is still running, so they don't finish and close, as I expected them being handled by the Watcher.
I can make things work with QtConcurrent::run !!!!
I am stuck.
Questions:
How can I make this QFuture / QFutureWatcher work ? What am I missing in my code or what am I doing wrong to make the threads not finish ?
How can I make the template non-void (to retrieve results easier ?)
I have m_futureWatcher.waitForFinished(); commented because that would block the GUI thread, I think - is that correct ?
Is there a better option to run multiple threads ? the word ThreadPool comes to mind but I have seen no examples that I can use - that can notify of completion. I did find a nice example to emulate a ThreadPool (NetResultsIT), but I expect Qt should have something functional.
When closing program, I get QThread: Destroyed while thread is still running. I was under the assumption that threads are closed when done, how should I clean up ? Is deleting the watcher enough ?
I am so lost, fighting these threads for over a week, and they're winning :( Thank you for any help or example.
Using Qt 5.15
Here is a simple example how QThreadPool works
#include <QThreadPool>
#include <QDebug>
#include <QApplication>
#include <QRunnable>
class MyRunnable : public QRunnable
{
public:
MyRunnable():QRunnable(){}
void run(){
for(int i = 0; i < 3; i++)
qDebug() << QThread::currentThreadId() << " i " << i;
}
};
int main(int argc, char *argv[]){
QApplication a(argc, argv);
QThreadPool::globalInstance()->start(new MyRunnable);
QThreadPool::globalInstance()->start(new MyRunnable);
QThreadPool::globalInstance()->start(new MyRunnable);
return 0;
}
output:
0x32c0 i 0
0x32f8 i 0
0x32f8 i 1
0x32f8 i 2
0x32c0 i 1
0x32c0 i 2
0x25a0 i 0
0x25a0 i 1
0x25a0 i 2
If I have a main thread and a separate, permanent worker QThread:
// Main thread where the event loop and QCoreApplication runs.
class NetworkController : public QObject {
public:
Q_OBJECT
void connect_to_ap()
{
WifiAP *myAP = netMgr.get_best_ap();
myAP->connect("my_psk_password");
}
// This is a class from a 3rd-party library, which contains, owns
// and manages the lifetime of "WifiAP" instances.
NetworkManager netMgr;
};
// Separate thread where a state machine runs.
class StateMachineWorker : public QObject {
public:
Q_OBJECT
void on_ready_to_connect_event()
{
// HERE: How to trigger NetworkController::connect_to_ap() and
// *block* until it returns.
}
NetworkController *pNetCtrlr;
}
When the state machine class enters a certain state it should connect to an AP (Access Point). The NetworkController has the functionality to connect to an AP.
I am trying to figure out a way that the state machine can do this in a thread-safe way. The problem is NetworkManager is always updating its list of WifiAP instances: they are created and destroyed often.
It would not be thread-safe for StateMachineWorker to call pNetCtrlr->connect_to_ap() directly (as the NetworkManager in the NetworkController thread could at the same time delete the WifiAP instance).
So what I would like is in StateMachineWorker::on_ready_to_connect_event() to somehow signal the NetworkController to run its connect_to_ap() method in NetworkController's own thread, and to block the StateMachineWorker thread until connect_to_ap() has finished doing its stuff. The reason I want the state machine to be blocked is if I did not block and let it enter the event loop, it could receive some event that would make it transition to another state before connect_to_ap() has finished executing; this must not happen.
Mutex locks to protect the list of WifiAP in NetworkManager would not work as they would need to be inserted inside the 3rd-party library.
You can use QMetaObject::invokeMethod with parameter Qt::BlockingQueuedConnection. This connection type adds all the blocking logic for you and you don't have to change the third party library at all.
A general example:
objects.h
#include <QObject>
#include <QThread>
#include <iostream>
class Object : public QObject {
Q_OBJECT
public slots:
void foo() {
std::cout << "Hello";
thread()->msleep(2000);
std::cout << " world!" << std::endl;
}
};
class Caller : public QObject {
Q_OBJECT
public:
void call(Object* o) {
std::cout << "Calling..." << std::endl;
metaObject()->invokeMethod(o, "foo", Qt::BlockingQueuedConnection);
std::cout << "Finished!" << std::endl;
}
};
main.cpp
#include <QCoreApplication>
#include "objects.h"
int main(int argc, char* argv[])
{
QCoreApplication a(argc, argv);
QThread t;
Object o;
o.moveToThread(&t);
t.start();
Caller().call(&o);
return a.exec();
}
The counterpart is that the method to be called must be a slot. If connect_to_ap is not already a slot you can create a bridge object that do the job, as explained below.
Have in mind that this bridge object must live in the same thread as the NetworkController (in your case the main thread), so the slot is queued in the correct events loop. You can take a look at QObject::moveToThread for further information.
A quick draft would be something like:
class NetworkControllerBridge : public QObject {
Q_OBJECT
NetworkController* nc;
public:
NetworkControllerBridge(NetworkController* nc_) : nc(nc_) {}
public slots:
void connect_to_ap() {
nc->connect_to_ap();
}
};
// ...
void on_ready_to_connect_event()
{
NetworkControllerBridge bridge(pNetCtrlr);
bridge.moveToThread(qApp->thread());
metaObject()->invokeMethod(&bridge, "connect_to_ap", Qt::BlockingQueuedConnection);
}
Update
Another way to call a method through invokeMethod is to mark it as Q_INVOKABLE. Although you still need the bridge since you cannot modify the library, I mention this for completeness of the answer.
Let's say I have a slave object that lives in another thread. I want to tell it to do A, B, C on that thread. I can think of 3 ways of doing it:
(1) Using QTimer::singleShot
(2) Using QMetaObject::invokeMethod
(3) Creating another master object and connecting its signal to the slave
Following is an example:
class slave : public QObject
{
QThread thread_;
friend class master;
void do_A(params);
void do_B(params);
void do_C(params);
public:
slave() { thread_.start(); moveToThread(&thread_); }
~slave() { thread_.quit(); thread_.wait(); }
void que_A(params) { QTimer::singleShot(0, [&](){ do_A(params); }); } // (1)
void que_B(params) { QMetaObject::invokeMethod(this, "do_B", params); } // (2)
}
class master : public QObject // (3)
{
Q_OBJECT
public:
master(slave* s) { connect(this, &master::que_C, s, &slave::do_C); }
void do_C(params) { emit que_C(params); }
signals:
void que_C(params);
}
My concerns are:
(1) I am abusing QTimer.
(2) Using strings for signals/slot is so qt4. Qt5 uses new syntax.
(3) Too much boilerplate.
Is any of the methods considered more correct compared to the others? Or can anybody think of a better way?
Please include your reasoning (not just opinion) why one method should be chosen over others.
UPDATE:
In my real-world application I have another class -- let's call it owner -- that owns several slaves. The owner needs to tell different slaves to do different things (A, B or C) depending on user input. The slaves are stateful objects, so I cannot see an easy way of using concurrency functions (eg, std::async or QtConcurrency).
Well, I will not comment (1) and (2) but I must say that (3) is the one usually used. However, I understand your concern about too much boilerplate. After all, creating a separate signal, say doActionA(), connecting it via QueuedConnection to some real actionA() and at last emitting it... too much noise and useless moves.
Indeed, the only benefit it gives you is a loose coupling (you can send a signal being not aware of existence of slots connected to it). But if I create a signal with a name doActionA() of course I am aware of actionA() existence. So then the question is starting to raise "Why do I have to write all this stuff?"
Meanwhile, Qt kind of provides the solution to this problem giving you the ability to post your own events to any event loop (and as you know QThread has one). So, implement it once and you do not need to write a lot of connect emit stuff any more. Also, I suppose I is more efficient because all in all, every slot invokation via QueuedConnection just posts an event in an event loop.
Here InvokeAsync posts the event for member function execution into the event loop of the thread where QObject lives:
#include <QCoreApplication>
#include <QEvent>
#include <QThread>
#include <string>
#include <iostream>
#include <type_traits>
#include <functional>
template<typename T, typename R, typename ... Params, typename... Args>
void InvokeAsync(T* object, R (T::*function)(Params...), Args&&... args)
{
struct Event : public QEvent
{
std::function<R ()> function;
Event(T* object, R (T::*function)(Params...), Args&& ... args)
: QEvent{ QEvent::None },
function{ std::bind(function, object, std::forward<Args>(args)...) }
{
}
~Event() { function(); }
};
QCoreApplication::postEvent(object, new Event{ object, function, std::forward<Args>(args)... });
}
struct Worker : QObject
{
void print(const std::string& message, int milliseconds)
{
QThread::currentThread()->msleep(milliseconds);
std::cout << message
<< " from thread "
<< QThread::currentThreadId() << std::endl;
}
};
int main(int argc, char* argv[])
{
QCoreApplication a(argc, argv);
std::cout << "GUI thread " << QThread::currentThreadId() << std::endl;
QThread thread;
thread.start();
Worker worker;
worker.moveToThread(&thread);
InvokeAsync(&worker, &Worker::print, "Job 1", 800);
InvokeAsync(&worker, &Worker::print, "Job 2", 400);
InvokeAsync(&worker, &Worker::print, "Job 3", 200);
a.exec();
return 0;
}
Output:
GUI thread 00000000000019C8
Job 1 from thread 00000000000032B8
Job 2 from thread 00000000000032B8
Job 3 from thread 00000000000032B8
As you see all jobs where done in a different thread in order of their invocation. Qt guarantees that events with the same priority are processed in order as they were posted.
Also it is OK, if worker lives in GUI thread. Events will be just posted in GUI event loop and processed later (that is why I called those Async).
If you see any mistakes or have some remarks, please, write in comments and we will figure it out.
I am not pretty sure I understood well the question.
So I will explain here how to manage thread in Qt (in summarized way).
First, QThreadclass is not really meant to be inherited from.
Instead, make something like this :
class Slave : public QObject {
Slave(QThread *thread) {moveToThread(thread);)
};
QThread thread;
Slave slave(&thread);
After, you normally can use signal and slots in the normal way.
However, if your objective is only to "run a function inside another thread", maybe QConcurrent could be a better way?
In fact, the Qt documentation provides a very nice example that probably answers your question on how to use QThread. It's the following:
class Worker : public QObject
{
Q_OBJECT
public slots:
void doWork(const QString ¶meter) {
QString result;
/* ... here is the expensive or blocking operation ... */
emit resultReady(result);
}
signals:
void resultReady(const QString &result);
};
class Controller : public QObject
{
Q_OBJECT
QThread workerThread;
public:
Controller() {
Worker *worker = new Worker;
worker->moveToThread(&workerThread);
connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
connect(this, &Controller::operate, worker, &Worker::doWork);
connect(worker, &Worker::resultReady, this, &Controller::handleResults);
workerThread.start();
}
~Controller() {
workerThread.quit();
workerThread.wait();
}
public slots:
void handleResults(const QString &);
signals:
void operate(const QString &);
};
The idea here is simple. You have a worker, which is running in the thread. You also have the controller, which is basically your main thread that submits work to the other thread. The thread will (thread-safely) emit the resultReady() signal when it's finished. Signals and slots are thread-safe here, as long as they use Qt::QueuedConnection to communicate.
I want to enable a pushbutton in a callback function. I have tried to do the following but I have got:
Runtime received SIGSEGV (address: 0x28 reason: address not mapped to object)
class MyWindow: public QDialog
{
Q_OBJECT
public:
QPushButton *Btn;
void Scan();
....
};
extern void StartScan(pfcallback);
void MyWindow::Scan()
{
Btn->setEnabled(false);
StartScan(Scanfinished);
}
void static Scanfinished()
{
Btn->setEnabled(true);
}
How to access the button in the callback function Scanfinished() ?
You're attempting to manually manage memory. As you can see, it's very easy to use a dangling pointer or commit other blunders. Instead, let the compiler do it for you.
You use static incorrectly.
If I were to do it, I'd do as follows. The destructor is generated by the compiler and will correctly release all resources and reset m_instance to a null value.
class MyWindow : public QDialog
{
Q_OBJECT
static QPointer<MyWindow> m_instance;
QVBoxLayout m_layout{this};
QPushButton m_button{"Scan"};
public:
MyWindow(QWidget * parent = nullptr) : QDialog(parent) {
Q_ASSERT(! m_instance);
m_instance = this;
m_layout.addWidget(&m_button);
}
void Scan();
static void ScanFinished();
};
QPointer<MyWindow> MyWindow::m_instance;
void StartScan(void(*callback)());
void MyWindow::Scan()
{
m_button.setEnabled(false);
StartScan(ScanFinished);
}
void MyWindow::ScanFinished()
{
m_instance->m_button.setEnabled(true);
}
At this point it's rather obvious that the API of StartScan is horribly broken, and this brokenness forces the use of a singleton MyWindow. When doing any kind of callbacks, you never use a sole C function pointer. You must accept both a function pointer that takes a void* and a void* that will be used to carry the data the function needs to work. This is an idiom. If you use C-style callbacks, you cannot not use the idiom without severely crippling the usability of your API.
Thus, this is a complete example and works in both Qt 4 and Qt 5. You should have posted something like it - a self-contained test case - in your question. It compiles and it works and you can even get the complete Qt Creator project from github. It will compile and run on all platforms supported by current Qt. It's not supposed to be hard: that's why you're using Qt, after all. Getting in the habit of creating such concise test cases to demonstrate your issues will make you a better developer, and make your questions much easier to answer.
// https://github.com/KubaO/stackoverflown/tree/master/questions/simple-callback-43094825
#include <QtGui>
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
#include <QtWidgets>
#include <QtConcurrent>
#endif
class MyWindow: public QDialog
{
Q_OBJECT
QVBoxLayout m_layout{this};
QPushButton m_button{"Scan"};
Q_SIGNAL void ScanFinished();
public:
MyWindow(QWidget * parent = nullptr) : QDialog(parent) {
m_layout.addWidget(&m_button);
connect(&m_button, SIGNAL(clicked(bool)), this, SLOT(Scan()));
connect(this, SIGNAL(ScanFinished()), this, SLOT(OnScanFinished()));
}
Q_SLOT void Scan();
static void ScanFinishedCallback(void* w);
Q_SLOT void OnScanFinished();
};
void StartScan(void(*callback)(void*), void* data) {
// Mockup of the scanning process: invoke the callback after a delay from
// a worker thread.
QtConcurrent::run([=]{
struct Helper : QThread { using QThread::sleep; };
Helper::sleep(2);
callback(data);
});
}
void MyWindow::Scan()
{
m_button.setEnabled(false);
StartScan(ScanFinishedCallback, static_cast<void*>(this));
}
void MyWindow::ScanFinishedCallback(void* data)
{
emit static_cast<MyWindow*>(data)->ScanFinished();
}
void MyWindow::OnScanFinished()
{
m_button.setEnabled(true);
}
int main(int argc, char ** argv) {
QApplication app(argc, argv);
MyWindow w;
w.show();
return app.exec();
}
#include "main.moc"
Of course StartScan cannot do the work in the thread it was called from: it'd block the GUI thread and make your application unresponsive. That's the prime source of bad user experience. Instead, it should spawn a concurrent job that will notify the caller when the scanning is done.
Since the callback will be called from that concurrent thread, it's not safe to use MyWindow's non-thread-safe methods. The only thread-safe methods are signals - thus we can emit a signal that Qt will the safely forward to MyWindow's thread and invoke OnScanFinished from the right thread.
I made a signal slot in Qt and the program runs without error or warnings about the connect i made. The problem is that when i want to use the signal slot, it always returns NULL.
Main.cpp
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Game* game = new Game;
Scrabble mainWindow;
mainWindow.show();
QObject::connect(&mainWindow,SIGNAL(getTurn()),game,SLOT(giveTurn()));
return a.exec();
}
Game.h
class Game: public QObject
{
Q_OBJECT
public:
Game(QObject *parent = 0);
~Game();
private:
int m_turn;
public slots:
int giveTurn();
};
Game.cpp
Game::Game(QObject *parent)
:QObject(parent)
{
m_turn = 1;
}
Game::~Game()
{
}
int Game::giveTurn()
{
return m_turn;
}
Scrabble.h
class Scrabble : public QMainWindow
{
Q_OBJECT
public:
explicit Scrabble(QWidget *parent = 0);
~Scrabble();
private:
Ui::Scrabble *ui;
signals:
int getTurn();
};
when i use int turn = emit getTurn(); in Scrabble.cpp, turn will become 0 and not 1.
Does anyone know what i'm doing wrong?
You're using signals and slots incorrectly. Signals cannot return value. See the Signals & Slots documentation page:
Signals are automatically generated by the moc and must not be implemented in the .cpp file. They can never have return types (i.e. use void).
Returning values from signals is not required when you use Qt features correctly. Maybe you should create another question and describe what you want to do and why you need such connection. You're definitely doing something wrong.
Signals/slots cant return any value. Possible solution:
Scrabble:
signal: void requestTurn();
public slot: receiveTurn(int);
Game:
public slot: onrequestTurn();
signal: sendTurn(int);
emit "keyword" is highly undocumented right now, but from Qt's source, it is only empty define, so your code
int turn = emit getTurn();
will be expanded to:
int turn = getTurn();
However, this is not covered in oficial documentation and it might change any time - so - don't use it!
Now, please note that turn variable is not getting value from slot, but from signal. There is nothing about passing return value from slot to signal - and it doesn't make sense (well, it may make sense in your sample, but what if I connect multiply slots to a single signal - what slot will return value, what if slots are executed asynchronously - should we wait for return value, etc.).
You can use regular function call (just call giveTurn() function: int turn = giveTurn()).