Call Qt object method from another std::thread - c++

I have simple Qt form which represents main window of my app. It has method:
void gui_popup::on_pushButton_clicked()
{
QString text = ui->MainText->toPlainText();
text = "1\n" + text;
ui->MainText->setText(text);
}
Also I have some code, running in another thread, created like this:
std:thread* core_thread = new thread(&Init); //void Init()...
Then, at some moment or condition code from std::thread need to call gui_popup::on_pushButton_clicked(). I'm trying to do it like this:
void test_callback(void* object_ptr)
{
auto this_object = (gui_popup*)object_ptr;
this_object->on_pushButton_clicked();
}
In std::thread code I'm saving test_callback pointer and gui_popup object pointer. But when it starts calling on_pushButton_clicked() program halts with segmentation fault error. This code works fine with some other simple classes, but not with QtObject. What am I doing wrong?
UPDATE:
I've solved it this way:
void test_callback(void* object_ptr)
{
QMetaObject qtmo;
qtmo.invokeMethod((gui_popup*)object_ptr, "on_pushButton_clicked");
}
it is, of course, much more complex than using QThread, emitting signals and all other suggested solutions. However thank you everyone for trying to help.

I usually solve it like this:
class Foo : public QObject
{
Q_OBJECT
Foo()
{
// connect to own signal to own slot and hence "translate" it
connect(this, SIGNAL(some_signal(QString)),
this, SLOT(some_slot(QString)));
}
signals:
void some_signal(QString s);
protected slots:
void some_slot(QString s)
{
// do something with your gui
}
public:
void callback_proxy(std::string s)
{
emit some_signal(QString::fromUtf8(m_string.c_str()));
}
};
and then the tread does not need to know about QT:
void thread_run_function(Foo* foo)
{
foo->callback_proxy("Hello from Thread!");
}
As far as I understood this is save because the connect (signal,slot) does have a additional default parameter (Qt::ConnectionType type which defaults to Qt::AutoConnection). This tells QT to dispach signals into the qt main event loop if they originate from a foreign thread. Note that using this connection type essentialy makes qt decide on runtime whether to dispatch the signal or call the slot immediately.
HtH Martin
Edits: Some more info on default parameter and this link as reference:
See http://doc.qt.io/qt-5/qt.html#ConnectionType-enum

Related

Qt Application Random Crashes via using callbacks and emitting signals from std::thread or boost::thread

I have an annoying issue with Qt and multi threading. Below I have created some simplified code. In my real code, the principle is exactlty the same but way too complex hence for using a simplified version.
The problem is that the application randomly crashes during different points at the run-time with different messages:
free(): invalid pointer
double free or corruption
The crash is triggered from within Qt, I will explain at the end of the post.
Here is how the code works.
So, I have classA that starts a thread:
class classA
{
public:
void start();
boost::function<void (std::string)> __ptr; // for callback
private:
boost::thread * thread;
void run();
};
void classA:start()
{
thread = new boost::thread(&classA::run, this); // start the thread
}
and here is the actual method that runs in the separate thread:
void classA::run()
{
for (int i = 0; i < 50000; i++)
{
static int count = 0;
__ptr("test123" + std::to_string(++count));
}
}
In my QDialog inherited class, I have a simple method that assigns the boot::function so I have declared another boost::function ptr. The problem is not with the ptr, it is with Qt, read on, the call back works just fine...
class myClassB : public QDialog
{
Q_OBJECT
public:
explicit myClassB (QWidget *parent);
classA ca;
private:
boost::function<void (std::string)> __ptr;
void mycallback(std::string);
};
In the constructor of myClassB, I am assigning my call back to boost::function like this (like I said, the callback works fine).
myClassB::myClassB()
{
this->__ptr = ( boost::bind( &myClassB::mycallback, this, _1 ) );
ca.__ptr = __ptr;
}
Here is where the problem starts. In my callback within my classB QDialog, I emit a Qt signal
void myClassB::mycallback(std::string txt)
{
emit sig_qt_data_received(txt);
}
This signal gets connected in my classB's constructor:
connect(this, SIGNAL(sig_qt_data_received(std::string)), this, SLOT(data_received(std::string)), Qt::DirectConnection);
and finally, the implementation of the Qt slot:
void myclassB::data_received(std::string txt)
{
ui->lbl_status->setText(txt);
}
This is where the problem is:
If you remove ui->lbl_status->setText(txt);, the program works flawlessly, it never crashes, if you leave it, it randomly crashes:
free(): invalid pointer
double free or corruption
It appears that the problem is within Qt as when I remove the setText() references, it does not crash and I have followed just about every GUI multi-threading procedure I have found and I don't know what I am doing wrong.
To connect the Qt signal, I am using Qt::DirectConnection and if I use Qt::AutoConnection it will work without a crash but sometimes the whole UI freezes (Edit: this is incorrect, see my answer).
I hope someone can help. If you need more code / real code, let me know, I will write an actual runnable code that you can run and compile but the fundamentals are the same, that's how the code works.
I don't want to be using QThread.
Resolved! Qt::DirectConnection was the culprit, now I use Qt::AutoConnection and it never crashes and according to the docs it is the default:
(Default) If the receiver lives in the thread that emits the signal,
Qt::DirectConnection is used. Otherwise, Qt::QueuedConnection is used.
The connection type is determined when the signal is emitted.
G.M's response above gave me the hint (Thanks):
the fact that explicitly specifying the connection type as
Qt::DirectConnection changes the behaviour suggests you've almost
certainly got a race condition due to threading
Also thank you jpo38 for suggesting / replying anyway.
Now I know I said sometimes it would freeze but no, that's incorrect, it never freezes, I had confused things.

SIGNALS and SLOTS in QT5

I've encountered a following issue:
I have a GUI element class and a Thread class. I would like to exchange signals between them. However it only works in one direction. I can successfuly send a signal from main GUI window to the thread. However when I want to send a signal from the thread to the process that calls the thread, but it doesn't work. Here is how I do it:
bool GfxMapItem::mapSwitch(int seqidx)
{
...
importMapThread_ = new ImportMapThread(sequence_->item(seqidx));
connect(GUI_UI->analExportButton, SIGNAL(clicked()), importMapThread_, SLOT(interrupt1()), Qt::QueuedConnection); //<-- this one works perfectly
connect(importMapThread_, SIGNAL(progress(int)), this, SLOT(loadMap(int)), , Qt::QueuedConnection); // <-- this one unfortunatelly doesn't
...
}
The thread code is very simple and it only emits the signal (I've check that it works when I connect the thread with itself).
void ImportMapThread::run()
{
QLOGX("Running ImportMapThread...");
QLOGINC;
emit this->progress(100);
QLOGX("Stopping ImportMapThread...");
}
The thread header looks like the one below:
class ImportMapThread : public InterruptibleThread
{
Q_OBJECT
private:
...
protected:
...
public:
ImportMapThread(SeqItem *p);
signals:
void progress(int value);
void progressReset(int value);
public slots:
virtual void interrupt1();
void loadMap();
protected:
virtual void run();
};
And the class that calls that thread looks like this:
class GfxMapItem : public QObject, public QGraphicsPixmapItem
{
Q_OBJECT
...
signals:
void mouseOutside();
void mouseMove(const QPointF &pos);
private slots:
void loadMap(int);
protected:
...
};
Any ideas? Please, I've ran out of ideas.
I believe, you should call exec in your run-implementation. Exec starts event-loop which should allow to send signals.
Take a look at:
int QThread::exec() [protected] Enters the event loop and waits until
exit() is called, returning the value that was passed to exit(). The
value returned is 0 if exit() is called via quit(). It is necessary to
call this function to start event handling.
I hope this helps.
Solved! It turned out that only the GUI elements can communicate with the threads. The thread can be inherited from other type of the thread and there isn't any problem neither with the signals nor the slots. The problem was laying in the object GfxMapItem. For some reason it just couldn't handle normal communication.

How to force Qt to update GUI from not main thread

I'm fighing since last week with problem caused by update of QPlainTextEdit. I'm trying to create separate from QMainWindow Dialog window with QPlainTextEdit inside. The problem begins when I try to use appendHtml signal (also tried with appendText), text that is placed is not visible unless marked by by mouse. Repainting or updating cause in program crash or no visible action.
Simplified code of QDialog with QPlainTextEdit header:
namespace Ui {
class LogWindow;
}
class LogWriter: public QDialog
{
Q_OBJECT
QMutex print_lock;
public:
class Log{
Q_OBJECT
const static int MAX_SIZE = 100;
bool to_terminal;
QString color;
QMutex *print_lock;
QPlainTextEdit *text_place;
QVector< QPair<QString,time_t> > history;
LogWriter * obj;
public:
bool print;
Log(bool _print,QString _color,LogWriter *obj_ = NULL)
{print = _print; color = _color; obj = obj_;}
void setLock(QMutex *print_lock_){print_lock = print_lock_;}
void setTextField(QPlainTextEdit *_text) {text_place = _text;}
Log& operator<<(QString &a);
Log& operator<<(const char* a);
};
static LogWriter* getInstance()
{
static LogWriter instance; // Guaranteed to be destroyed.
// Instantiated on first use.
return &instance;
}
~LogWriter();
Log LOW,MEDIUM,HIGH;
Ui::LogWindow *ui;
signals:
void signalLogAppend(QString);
};
Simplified code of methods definitions:
LogWriter::LogWriter(QWidget * parent): QDialog(parent) {
ui = new Ui::LogWindow;
ui->setupUi(this);
LOW.setLock(&print_lock);
MEDIUM.setLock(&print_lock);
HIGH.setLock(&print_lock);
connect(this,SIGNAL(signalLogAppend(QString)),ui->plainTextEdit,
SLOT(appendHtml(QString)),Qt::DirectConnection);
}
LogWriter::Log& LogWriter::Log::operator<< (QString &s){
history.push_front(qMakePair(s,time(NULL)));
if(history.size() > MAX_SIZE) history.pop_back();
if(print){
//print_lock->lock();
QString text = "<font color=\"";
text += color + "\">";
text += s + "</font>";
//cout << text.toStdString() << endl;
//text_place->appendHtml(text);
//text_place->repaint();
emit (obj)->signalLogAppend(text);
//print_lock->unlock();
}
return *this;
}
I have two separate ui files (first for main window, second for log window).
I have to use log window all across my program (something about 10 threads), and I stucked on this issue. My question is - is it possible to force GUI update without using main thread and if not - what else possibilities I have. If possible I would rather avoid reconstructing all my code - it would take me some time to do it. Right now logging is super easy - I ony need:
LogWindow *log = LogWindow::getInstance();
log->MEDIUM << "something";
As additional info I add QTCreator warning:
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().)
If I understand your code correctly, you're trying to log from a background thread and are using a direct connection to pass the signal to the GUI thread? That's not going to work, you have to send the signal via the default connection so Qt can figure out that it's a cross-thread signal and pass it across threads accordingly (ie, via the message loop on the foreground thread).
In Qt, any GUI interaction has to happen in the Main/foreground thread otherwise bad things happen as you discovered. You can certainly send a signal from a background thread to trigger a GUI update - I do this all the time - but you need to ensure that you're using the correct connection for it. The direct connection results in a direct function call and is not going to work for you in this case.
In your code, the problem is the call to connect() - you explicitly specify the connection mode for the signal to slot connection when you should just use the default setting. If you set the connection explicitly to Qt::DirectConnection, the underlying code will execute a direct call to the specified slot, which means that you end up calling the slot in the thread context of the signal. You don't want that because the signal is triggered in a background thread.
You can't pass arbitrary types/classes to signals and slots. The list is limited and not all Qt classes are in the list. To add types/classes to the list of those that can be passed to a signal/slot, you must call qRegisterMetaType for that class. I recommend calling it in the constructor of the class you're trying to pass to a signal like this:
MyClass::MyClass() : MyParentClass()
{
static int reg = qRegisterMetaType<MyClass>("MyClass");
}
The static int ensures the registration is only called once and before any instance of MyClass could ever be used.

Can Qt signals return a value?

Boost.Signals allows various strategies of using the return values of slots to form the return value of the signal. E.g. adding them, forming a vector out of them, or returning the last one.
The common wisdom (expressed in the Qt documentation [EDIT: as well as some answers to this question ]) is that no such thing is possible with Qt signals.
However, when I run the moc on the following class definition:
class Object : public QObject {
Q_OBJECT
public:
explicit Object( QObject * parent=0 )
: QObject( parent ) {}
public Q_SLOTS:
void voidSlot();
int intSlot();
Q_SIGNALS:
void voidSignal();
int intSignal();
};
Not only doesn't moc complain about the signal with the non-void return type, it seems to actively implement it in such a way as to allow a return value to pass:
// SIGNAL 1
int Object::intSignal()
{
int _t0;
void *_a[] = { const_cast<void*>(reinterpret_cast<const void*>(&_t0)) };
QMetaObject::activate(this, &staticMetaObject, 1, _a);
return _t0;
}
So: according to the docs, this thing isn't possible. Then what is moc doing here?
Slots can have return values, so can we connect a slot with a return value to a signal with a return value now? May that be possible, after all? If so, is it useful?
EDIT: I'm not asking for workarounds, so please don't provide any.
EDIT: It obviously isn't useful in Qt::QueuedConnection mode (neither is the QPrintPreviewWidget API, though, and still it exists and is useful). But what about Qt::DirectConnection and Qt::BlockingQueuedConnection (or Qt::AutoConnection, when it resolves to Qt::DirectConnection).
OK. So, I did a little more investigating. Seems this is possible. I was able to emit a signal, and receive value from the slot the signal was connected to. But, the problem was that it only returned the last return value from the multiple connected slots:
Here's a simple class definition (main.cpp):
#include <QObject>
#include <QDebug>
class TestClass : public QObject
{
Q_OBJECT
public:
TestClass();
Q_SIGNALS:
QString testSignal();
public Q_SLOTS:
QString testSlot1() {
return QLatin1String("testSlot1");
}
QString testSlot2() {
return QLatin1String("testSlot2");
}
};
TestClass::TestClass() {
connect(this, SIGNAL(testSignal()), this, SLOT(testSlot1()));
connect(this, SIGNAL(testSignal()), this, SLOT(testSlot2()));
QString a = emit testSignal();
qDebug() << a;
}
int main() {
TestClass a;
}
#include "main.moc"
When main runs, it constructs one of the test classes. The constructor wires up two slots to the testSignal signal, and then emits the signal. It captures the return value from the slot(s) invoked.
Unfortunately, you only get the last return value. If you evaluate the code above, you'll get: "testSlot2", the last return value from the connected slots of the signal.
Here's why. Qt Signals are a syntax sugared interface to the signaling pattern. Slots are the recipients of a signal. In a direct connected signal-slot relationship, you could think of it similar to (pseudo-code):
foreach slot in connectedSlotsForSignal(signal):
value = invoke slot with parameters from signal
return value
Obviously the moc does a little more to help in this process (rudimentary type checking, etc), but this helps paint the picture.
No, they can't.
Boost::signals are quite different from those in Qt. The former provide an advanced callback mechanism, whereas the latter implement the signaling idiom. In the context of multithreading, Qt's (cross-threaded) signals depend on message queues, so they are called asynchronously at some (unknown to the emitter's thread) point in time.
Qt's qt_metacall function returns an integer status code. Because of this, I believe this makes an actual return value impossible (unless you fudge around with the meta object system and moc files after precompilation).
You do, however, have normal function parameters at your disposal. It should be possible to modify your code in such a way to use "out" parameters that act as your "return".
void ClassObj::method(return_type * return_)
{
...
if(return_) *return_ = ...;
}
// somewhere else in the code...
return_type ret;
emit this->method(&ret);
You may get a return value from Qt signal with the following code:
My example shows how to use a Qt signal to read the text of a QLineEdit.
I'm just extending what #jordan has proposed:
It should be possible to modify your code in such a way to use "out" parameters that act as your "return".
#include <QtCore>
#include <QtGui>
class SignalsRet : public QObject
{
Q_OBJECT
public:
SignalsRet()
{
connect(this, SIGNAL(Get(QString*)), SLOT(GetCurrentThread(QString*)), Qt::DirectConnection);
connect(this, SIGNAL(GetFromAnotherThread(QString*)), SLOT(ReadObject(QString*)), Qt::BlockingQueuedConnection);
edit.setText("This is a test");
}
public slots:
QString call()
{
QString text;
emit Get(&text);
return text;
}
signals:
void Get(QString *value);
void GetFromAnotherThread(QString *value);
private slots:
void GetCurrentThread(QString *value)
{
QThread *thread = QThread::currentThread();
QThread *mainthread = this->thread();
if(thread == mainthread) //Signal called from the same thread that SignalsRet class was living
ReadObject(value);
else //Signal called from another thread
emit GetFromAnotherThread(value);
}
void ReadObject(QString *value)
{
QString text = edit.text();
*value = text;
}
private:
QLineEdit edit;
};
To use this, just request call();.
You can try to workaround this with following:
All your connected slots must save their results in some place (container) accessible from signaling object
The last connected slot should somehow (select max or last value) process collected values and expose the only one
The emitting object can try to access this result
Just as an idea.

Display a QMessageBox from C code running in a QThread

I have the main (GUI) thread which creates a QThread.
In the QThread, I am calling a C function that needs to display a QMessageBox. So far, I simply used:
void notify(char *str)
{
QMessageBox::information(0, "", QString(str));
}
in the C++ code and called it from the C code. This worked fine without threads, but now with threads I am getting errors, because one cannot call the GUI functions from another thread.
Usually, this could be circumvented by using signals like the answer to this question suggests; however, I doubt I can do this from the C code.
So, how can I make the C code communicate with the GUI thread and tell it to display a QMessageBox?
Thanks.
P.S.
If possible, I'd like to do this without touching the C code (as of now, there is simply an extern void notify(char *) declaration in the C code's headers, and if possible I'd like it to stay at that.
Assuming you have a QWidget or QMainWindow derived class for your GUI, you could add the following to it:
class MyWidget : public QWidget
{
Q_OBJECT;
public:
MyWidget()
{
connect(this, SIGNAL(notify_sig(QString)),
this, SLOT(notify_slot(QString)),
Qt::QueuedConnection);
}
void notify(QString str)
{
emit notify_sig(str);
}
signals:
void notify_sig(QString str);
slots:
void notify_slot(QString str)
{
QMessageBox::information(0, "", str);
}
};
Here you have a public function notify() that is a member of the widget class. Calling MyWidget::notify() results in a signal being sent to itself through a queued connection (which will result in the slot being called in the GUI thread). Now the C notify() call just needs to call the widget/window's notify() function. This can be tricky since you don't really have a pointer to the widget available in the C notify() function.
Normally, the C interface would allow the user to pass a void* value in and would then return that value with the notify call. This would allow you to pass in the pointer to MyWidget when the C function is called and then cast it back to MyWidget in the notify() implementation.
MyWidget* wid = ...;
C_function(arg1, ..., wid);
//...
void notify(char* str, void* userdata)
{
MyWidget* wid = static_cast<MyWidget*>(userdata);
wid->notify(QString(str));
}
If you can't change the C interface, you may need to use some kind of global way of getting the widget/window's pointer.
Note that I have not tested any of this code and there may be an easier way to do this.