Updating pointer using signals and slots - c++

I am very new to Qt; please help me to solve the problem.
I am using a thread to perform intensive operations in the background. Meanwhile I want to update the UI, so I am using SIGNALS and SLOTS. To update UI I emit a signal and update UI.
Let us consider below sample code,
struct sample
{
QString name;
QString address;
};
void Update(sample *);
void sampleFunction()
{
sample a;
a.name = "Sachin Tendulkar";
a.address = "India"
emit Update(&a);
}
In the above code we are creating a local object and passing the address of a local object. In the Qt document, it says that when we emit a signal it will be placed in the queue and late it will be delivered to the windows. Since my object is in local scope it will be delete once it goes out of the scope.
Is there a way to send a pointer in a signal?

You're insisting on doing the wrong thing, why? Just send the Sample itself:
void Update(sample);
//...
sample a("MSalters", "the Netherlands");
emit Update(a);

Unless you've determined that this code is a performance bottleneck you would be better to just pass a copy of the object rather than a pointer.
Really, I mean it.
However, if you must use pointers then use a boost::shared_ptr and it will delete itself.
void Update(boost::shared_ptr<sample> s);
void sampleFunction()
{
boost::shared_ptr<sample> a = boost::shared_ptr<sample>(new sample());
a->name = "Sachin Tendulkar";
a->address = "India"
emit Update(a);
}

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.

Smart pointers as an alternative to QObject::deleteLater()

So I have got a function which makes a network request:
void MyClass::makeRequest()
{
ApiRequest* apiRequest = new ApiRequest();
apiRequest->makeRequest();
connect(apiRequest, &ApiRequest::requestFinished, this, &MyClass:onApiRequestFinished);
}
Since I need the object apiRequest to survive until my request is finished I then call:
void MyClass:onApiRequestFinished()
{
// do my stuff
// now I can delete my request object ((retrieved using sender()) using deleteLater()
}
Now since I am not using Qt parent-child system in this case how can I manage the memory using C++11 smart pointers instead of calling deleteLater()?
I don't think you can solve this with C++ smart pointers without storing the apiRequest object in some container until requestFinished is triggered.
Maybe an alternative would be to create an ApiRequest::finished() method to use as the receiver of the signal, then pass this to ApiRequest's constructor so finished() can call MyClass::onApiRequestFinished(), and then have finished() call delete this after onApiRequestFinished() exits, eg:
void MyClass::makeRequest()
{
ApiRequest* apiRequest = new ApiRequest(this);
apiRequest->makeRequest();
}
void MyClass::onApiRequestFinished()
{
// do my stuff
}
...
ApiRequest::ApiRequest(MyClass *cls)
: m_cls(cls)
{
connect(this, &ApiRequest::requestFinished, this, &ApiRequest::finished);
}
void ApiRequest::finished()
{
m_cls->onApiRequestFinished();
delete this;
}
Not sure how feasible this is with Qt, but maybe worth a try.

slot is called multiple times when signal is emitted

Consider functions like below:
class1::class1()
{
class3 obj3 = new class3(this);
}
void class1::function1()
{
class2 *obj2 = new class2();
connect(obj3, SIGNAL(sig()), obj2, SLOT(slt()));
}
void class3::function2()
{
emit sig();
}
I am invoking function1() multiple times.
function2() is also triggered multiple times
What I want is, whenever sig() is emitted slt() should be called, but what's happening is, first time when sig() is emitted slt() is being called number of times function1() is invoked.
Next time when sig() is invoked slt() is not called.
It would be a great help, if somebody can help me achieve this.....
You should only call connect once. Move your code that calls connect to a different function that is only called once.
So I´m not sure you understand what you are doing or what you want. So I´ll explain what is happening and then we can rethink what you want. Qt is working as expected. You said you want the slot to be called whenever the signal is emitted. That is exactly what your code is doing.
Now the question is ... are you aware that you create a new instance of your class2 each time function1 is called? Are you sure you didn´t just want a single instance of class2? Because that would then behave more in the way that you want it to.
class2 *obj = 0;
void class1::function1()
{
if(!obj)
{
obj = new class2();
connect(this, SIGNAL(sig()), obj, SLOT(slt()));
}
}
void class2::function2()
{
emit sig();
}
Since I have no idea where you create an object of class1, I just gave you something based on what you gave us. This should behave in the way you want it to. If that confuses you, I would suggest you should google some tutorials on learning C++, or object oriented programming (OOP) for that matter. Unfortunately I cannot recommend you any books/tutorials or else I would.
I hope this helps you.

Call Qt object method from another std::thread

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

Public member not initialized

I am making a client server application, with the server having a GUI. I am using Qt.
For communication I am using pipes.
I have divided the server application into a backend, and a GUI. The backend has a PipeServer class, and in the GUI, I have overriden functions like onReceiveMessage etc.
Everything worked fine until I decided to add a std::queue as a base class member.
At the start of the application, I get an exception, and upon inspection it seems that my queue does not start with 0 elements. In fact it seems like the queue is not initialized at all. There are 2 possibilites: it could be because I the GUI class inherits 2 classes, and somehow the second base class, which is my PipeServer does not properly initialize its members, or it could be because the pipeServerGUI object is moved to a different thread by QT.
Any ideas on how I could solve this?
Relevant code:
class HookServer
{
PIPEINST Pipe[INSTANCES];
HANDLE hEvents[INSTANCES];
VOID DisconnectAndReconnect(DWORD);
BOOL ConnectToNewClient(HANDLE, LPOVERLAPPED);
VOID GetAnswerToRequest(LPPIPEINST);
public:
std::queue<std::string> messages;
int init(std::string pipename);
int run();
virtual void onNewConnection() {};
virtual void onReceiveMessage(std::string message) {};
};
class HookServerGUI : public QObject, public HookServer
{
Q_OBJECT
void onReceiveMessage(std::string message);
void onNewConnection();
public slots:
void doWork() {
init("\\\\.\\pipe\\hookpipe");
run();
}
signals:
void signalGUI(QString message);
};
//GUIServerCreation
QThread *thread = new QThread;
HookServerGUI* worker = new HookServerGUI;
QObject::connect(worker,SIGNAL(signalGUI(const QString&)),this,SLOT(processMessage(const QString&)));
worker->moveToThread(thread);
thread->start();
QMetaObject::invokeMethod(worker, "doWork", Qt::QueuedConnection);
EDIT:
The exception is a access violation exception. It happens in this part of code:
VOID HookServer::GetAnswerToRequest(LPPIPEINST pipe)
{
onReceiveMessage(pipe->chRequest);
if(!messages.empty())
{
std::string s = messages.front();
messages.pop();
strcpy(pipe->chReply,s.c_str());
pipe->cbToWrite = strlen(s.c_str()+1);
}
}
Since messages.empty() return some huge number, it tries to read the first object and somehow fails.
There is also no PipeServerGUI constructor.
EDIT2:
I solved part of this problem by placing parenthesis after new HookServerGUI();
The problem is that still the function does not work, and throws a access violation exception. It happens on the front() line. When checked in a debugger, the function does have 1 element, so it is not because it is empty. Any ideas?
EDIT3:
With the second run, unfortunately the queue.size() is still incorrect. Seems like a data race to me.
The problems are in the code that you don't show, and it's a classic case of a memory bug, it looks like. Some code somewhere is writing on memory it doesn't own. Probably you have a bug in the way you use winapi. You need to create a minimal, self-contained test case.
I think you might be shooting yourself in the foot by not using QLocalSocket: on Windows, it's a named pipe - exactly what you want.
Besides, this is C++ code. There is no reason at all to put either PIPEINST or HANDLE into a raw C array. Use QVector or std::vector. Probably the rest of the code is full of C-isms like that, and something somewhere goes wrong.
I wouldn't discount a buffer overrun, since obviously you are ignoring the size of the buffer in PIPEINST from the - the strcpy can overrun the buffer. I'm also not sure that PIPEINST from the example code is using the same character type as what std::string::c_str() is returning.
Even if you wanted to implement your code using explicit pipes without QLocalSocket, you should still use C++, QString etc. and understand what's going on with your data.