I want to emit a signal from a C++ thread (std::thread) in Qt.
How can I do it?
You definitely can emit a signal from a thread (QThread, std::thread or even boost::thread). Only you must be careful of your connect function's fifth parameter (Qt::ConnectionType):
If Qt::DirectConnection: The slot is invoked immediately (from the current thread), when the signal is emitted.
If Qt::QueuedConnection: The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread.
See ConnectionType-enum for more options.
The problem is not really from which thread you emit the signal, it's more from which thread the slot is being invoked. For instance, I think QLabel::setText must be executed from QLabel's owner thread (most likely main thread). So if you emit a signal connected to a QLabel's setText from a thread, connection must be done with Qt::AutoConnection, Qt::QueuedConnection or Qt::BlockingQueuedConnection.
You probably should not emit a Qt signal from a std::thread-created thread in general without care. See Jpo38's answer : connection type matters, etc...
If the thread is running some Qt event loop, you probably could. See threads and QObject
There is a (Unix-specific probably) work-around, doing the same as for Unix signals with Qt : use a pipe from your std::thread to the main thread.
But, as commented by Joachim Pileborg, you should make your own QThread. It is the simplest, and probably the shortest (in term of source code), and you just need to copy and paste some existing example and adapt it to your need.
Beware that AFAIK only the main thread should do Qt GUI manipulations. You should not use any QWidget (etc...) outside of the main thread! (BTW, GTK has the same restriction, at least on Linux: only the main thread is supposed to use the X Windows system protocols)
If you're keeping pointer to your QObject then you could use one of QMetaObject::invokeMethod member http://qt-project.org/doc/qt-5/qmetaobject.html#invokeMethod
Probably you will have to use Qt::QueuedConnection so your signal will be invoked at proper thread (not your std::thread). Remember that your signal won't be invoked immedietly.
class MainForm : public QMainWindow
{
Q_OBJECT
public:
explicit MainForm(QWidget *parent = nullptr);
virtual ~MainForm();
private:
signals:
void signalSendButtonEnable(bool);
private slots:
void singalReceiveButtonEnable(bool);
};
MainForm::MainForm(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainForm), status_{false}, io_context_{}, timer_{io_context_}
{
ui->setupUi(this);
// bind SIGNAL & SLOT
connect(this, SIGNAL(signalSendButtonEnable(bool)), this, SLOT(singalReceiveButtonEnable(bool)));
}
MainForm::~MainForm()
{
delete ui;
}
void MainForm::singalReceiveButtonEnable(bool status){ //recv signal
qDebug() << "singalReceiveButtonEnable";
this->ui->btnConnect->setEnabled(status);
}
void MainForm::start(){
std::thread t([](){
sleep(20);
emit signalSendButtonEnable(true); //send signal
});
t.detach();
}
Related
i've created a thread in QT using QThread but the parent of the thread is exiting before the thread finishes which itself is running infifnitely.
//mainwindow.cpp
void MainWindow::showEvent(QShowEvent *ev)
{
QMainWindow::showEvent(ev);
showEventHelper();
}
void MainWindow::showEventHelper()
{
//back-end thread
ServerStart *serverstart = new ServerStart();//initializing a pointer to my class
QThread thread;
serverstart->moveToThread(&thread);
QObject::connect(&thread, &QThread::started, serverstart, &ServerStart::run);
thread.start();
//in std::thread i used to detache it like so:
//std::thread worker(serverMain);
//worker.detach();
}
IMPORTANT: I'm making a GUI project. and my infinite thread is inside an onShow() method that needs to exit in order for the app to continue and make the UI. and I also want to send signals in the future from the thread to the main thread and the main thread should be able to respond and modify the UI according to the signal.
how can i do the same in QT?
You can't, however according to KDAB documentation of proper QThread usage you can emulate such behavior by connecting QThread::finished to QThead::deleteLater as shown from their document for QThread here https://www.kdab.com/wp-content/uploads/stories/multithreading-with-qt-1.pdf
Qt doc:
If no event loop is running, events won't be delivered to the object.
For example, if you create a QTimer object in a thread but never call
exec(), the QTimer will never emit its timeout() signal. Calling
deleteLater() won't work either. (These restrictions apply to the main
thread as well.)
Does this mean that signal void QTimer::timeout() will also issue a QEvent?
If so, where does the Qt doc state this?
where does the Qt doc state this?
Nowhere, because it shouldn't matter to the user of QTimer. The timer event is an implementation detail. It is delivered to the timer object itself, so you'd really have to go out of your way to intercept it. Here's how QTimer works:
class QTimer : public QObject {
Q_TIMER
QBasicTimer m_timer;
protected:
void timerEvent(QTimerEvent * ev) override {
if (ev->timerId() == m_timer.timerId())
emit timeout();
}
/*...*/
};
If you think about it, there's no way of emitting any signals without running the code that emits the signals, and the only way to safely run such code that emits things asynchronously is to code for run-to-completion chunks that cede control to the event loop at every opportunity. The event loop is notified by the platform that a timer has timed out, and emits a signal right then. You'd be in deep trouble if Qt issued signals such as timer timeouts from intrusive asynchronous callbacks like Unix signals: just read about how few things you can do while in a signal handler - it'd be no different than an interrupt handler.
I have a class ParentThread deriving from QThread with the following run() method that roughly looks as follows:
void ParentThread::run()
{
QThread *childThread = new QThread;
QObject::connect(childThread, SIGNAL(finished()), this, SLOT(onChildThreadFinished());
QObject::connect(childThread, SIGNAL(finished()), childThread, SLOT(deleteLater());
childThread->start();
exec();
}
The slot onChildThreadFinished() is defined on ParentThread, and should run in the context of ParentThread. However, using the code above, onChildThreadFinished only gets called in case the signal/slot connection is a Qt::DirectConnection, but then runs in the context of the child thread. In case the signal/slot connection is defined as a Qt::QueuedConnection, the slot never gets called. I am using Qt 4.8.5. Any idea what the issue is here?
You state that The slot onChildThreadFinished() is defined on ParentThread, and should run in the context of ParentThread. This assumption is wrong. This is one of the reasons why subclassing QThread is discouraged.
If you want to use slots in your threads, subclassing QThread is not what you want to do. Use worker-object method instead. Subclass QObject and call QObject::moveToThread to move your object to a new thread.
Here is what Qt docs say about this:
It is important to remember that a QThread instance lives in the old thread that instantiated it, not in the new thread that calls run(). This means that all of QThread's queued slots will execute in the old thread. Thus, a developer who wishes to invoke slots in the new thread must use the worker-object approach; new slots should not be implemented directly into a subclassed QThread.
I'm trying to use signals and slots to pass information to the GUI thread from another thread, as I can't modify a pixmap from any other thread. I'm encountering a runtime error:
Object::connect: No such signal QThread::image_change(std::string) in visualiser.cpp:33
Judging from this, though I may be wrong, it looks like the signal is being searched for in the wrong namespace, as it is actually defined in Visualiser::image_change().
My code is as follows:
Visualiser.cpp:
QFutureWatcher<void> watcher;
connect(watcher.thread(), SIGNAL(image_change(std::string)), QCoreApplication::instance()->thread(), SLOT(update_image(std::string)), Qt::QueuedConnection);
QFuture<void> update_thread = QtConcurrent::run(this, &Visualiser::update_state);
watcher.setFuture(update_thread);
...
emit(image_change(imageSrc));
...
void Visualiser::update_image(std::string src)
{
QImage image;
image.load(src.c_str());
ui->visualContainer->setPixmap(QPixmap::fromImage(image));
}
visualiser.h:
signals:
void image_change(std::string src);
public slots:
void update_image(std::string src);
Don't pass thread pointers into connect - pass pointers to the sender and receiver of the event (like this). Because you're giving it QThread pointers instead, Qt is looking for those signals and slots in QThread, where they don't exist. If you give it Visualizer pointers instead, Qt will look for those functions in Visualizer, where they really are, and everything will work.
Hope that helps!
The source and the target of the connection are the same object, this, so the connect call should be:
connect(this, SIGNAL(image_change(std::string)), this, SLOT(update_image(std::string)));
Since the signal will be emitted from another thread than the one the Visualizer has an affinity with (see QObject::moveToThread()), the connection with the slot will automatically be queued, and the slot will be executed by the correct thread.
But for queued connection to work, Qt has to store temporarily the parameter until it can actually call the slot, which is done by converting it to QVariant, storing it somewhere, and then reconverting it to the actual type when the receiving thread is ready to execute the slot.
So you need to register std::string to Qt's metatype system with Q_DECLARE_METATYPE or change the signal and slot parameter type to one that is already registered to (like QString or QByteArray).
I will keep the code simple so that you guys can see what I'm trying to do ;)
I am aware of all of the locking issues, etc. I'm trying to figure out how signals and slots play with threads.
In main.cpp:
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
MyConsole c; // Subclasses QThread and implements run()
MyReceiver r(app); // We pass app to MyReceiver for later (see below)
QObject::connect(&c, SIGNAL(sendit()),
&r, SLOT(gotit()));
c.start(); // Start the worker thread
app.exec();
}
Assume that the signals and slots were properly set up in the header files (I've tested and they are). Now, here's the issue:
In MyReceiver.cpp:
void MyReceiver::gotit()
{
QLabel *label = new QLabel(0, "Hello"); // Some GUI element, any will do
app.setMainWidget(*label); // Some GUI action, any will do
}
The question is: Because the MyReceiver object was created in main(), which is on the main thread, does that mean that the slots (e.g., gotit()) will run on the main thread and are therefore safe for doing GUI stuff? Even in cases where the signal was raised from a different QThread (like MyConsole in this example)?
Is there a better way to allow worker threads to interact with the GUI (for example, Obj-C/Cocoa have a "send message on main thread" type of approach). What is "The Qt way" of doing this?
Thanks in advance!
By default (Qt::AutoConnection), slots will run in the thread the QObject was created in. So, no matter from what thread you emit the signal, the slot will be run always in the thread, the QObject "lives" in (if a Qt event loop is running in that thread, otherwise the event can't be delivered). Since the main thread will become the Qt GUI thread, this will work as expected. This is indeed the Qt way of interacting with the GUI.
See also: http://doc.qt.nokia.com/4.7/thread-basics.html (look for thread affinity).
The "Qt way" to emit a signal from one thread and receive it in a different thread is to use a Queued connection
connect( obj, SIGNAL(foo()), other_obj, SLOT(bar()), Qt::QueuedConnection )
From the Qt documentation for Qt::QueuedConnection:
The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread.