PDA

View Full Version : Qt/Qml + RTI DDS Application



PascalSevran
30th April 2014, 14:28
Hi,

I'm currently making a small application using QtCreator where I use RTI DDS to implement some simple request/reply communications.
By clicking on a simple button from a qml designed GUI, I'd like to send a request using a RTI DDS "requester" and then receiving and displaying the reply by using a RTI DDS "replier".

So I created my DDS requester and replier classes, both unheriting from QObject, and made the link with the qml part using setContextProperty.

My problem now is that I'm not very sure what is the right way of using QThreads to launch in paralel both the requester and the replier in a proper way.

What I did for now, which seems to be half working and not very proper is :

In my main :


int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QtQuick2ApplicationViewer viewer;

requester req;
replier rep;

QThread requesterThread;
QThread replierThread;

req.moveToThread(&requesterThread);
rep.moveToThread(&replierThread);

req.connect(&requesterThread, SIGNAL(started()), SLOT(runReq())); //where runReq() is the main method of my requester class
rep.connect(&replierThread, SIGNAL(started()), SLOT(runRep()));

req.connect(&requesterThread,SIGNAL(finished()),SLOT(deleteLate r()));
rep.connect(&replierThread,SIGNAL(finished()),SLOT(deleteLater( )));

&requesterThread.connect(&requesterThread,SIGNAL(finished()),SLOT(deleteLate r()));
&replierThread.connect(&replierThread,SIGNAL(finished()),SLOT(deleteLater( )));


//Setting context properties
viewer.rootContext()->setContextProperty("requester",&req );
viewer.rootContext()->setContextProperty("replier", &rep);

viewer.rootContext()->setContextProperty("requesterTHREAD",&requesterThread );
viewer.rootContext()->setContextProperty("replierTHREAD", &replierThread);


viewer.setMainQmlFile(QStringLiteral("qml/ProjectUsecase1/main.qml"));
viewer.showExpanded();

return app.exec();


And then I call : requesterThread.start() and replierThread.start() in my main.qml when the button is clicked.

So, I'm pretty sure there's a better way to create and destroy the threads, anywhere but in the main.cpp. Should I create a class dedicated to the management of my threads ? What's the cleaniest way to destroy the threads after the requester's and replier's execution ?

Thank you very much by advance.

anda_skoa
30th April 2014, 17:49
Are requester::runReq() and replier::runRep blocking?

I.e. what is the reason you are using threads?

Cheers,
_

PascalSevran
5th May 2014, 09:52
Hello, yes, the runReq() function blocks until it receives a reply and the runRep() blocks until it receives a request.

With a similar project under Visual Studio, I gotta open both the requester.exe an the replier.exe in different cmd prompts to enable the communication between them.
With my Qt project I'd like to launch them and make them communicate with a simple click from my GUI, that's why I thought using threads was the only way, if it's not I'm opened to any suggestions :)

anda_skoa
5th May 2014, 11:34
I was mainly asking because the use of the moveToThread() approach suggests that the thread should use its default event loop.

Is the UI just triggering the start of the operations or is it somehow getting values back at some point?

Cheers,
_

PascalSevran
5th May 2014, 11:55
The UI shall display the results, so yes, the result of the request is theorically able to be available by the qml side thanks to setContextProperty(). However I notices that my UI isnt refreshing dynamically once the result is available, I read somewhere that I shall use QAbstractItemModel instead of setContextProperty().

As far as the threads are concerned, despite my use of the connect() method with the deleteLater() in the main.cpp, they don't seem to end properly and that's what is bothering me :(

anda_skoa
5th May 2014, 13:49
A model would most likely also be exposed as a context property, it really depends on how your result is created and how it is communicated to the QML scene.

How do you currently do that?

Cheers,
_

P.S.: Your connect finished->deleteLater is never triggered, since the threads are not told to quit.

PascalSevran
5th May 2014, 15:36
The result is generated by the DDS replier, then it is sent back to the DDS requester. When I receive it, I copy the value in a m_reqResult var, which is accessible from qml thanks to the setContextProperty() and the line :


Q_PROPERTY(int m_reqResult READ getResult WRITE setResult NOTIFY resultChanged) in my requester class.

For the threads, should I emit a finished() signal in the end of my runReq() and runRep() functions ?

Thanks a lot

anda_skoa
5th May 2014, 17:22
Since your thread payload is "run once" and blocking it is probably cleaner to reimplement QThread::run() instead of "abusing" a thread with event loop, but yes, emitting signal at the end of the payload function should work as well.

Cheers,
_

PascalSevran
6th May 2014, 10:00
Ok so you're saying that instead of making the slot runReq() do the work I should transfer this work to the QThread::run() function which I can call since my requester class inherits from QObject, right ?

Thanks

anda_skoa
6th May 2014, 10:57
I am not quite sure I understand the question.

QThread::run() is executed by the new thread, its context is a lot like main().

The only thing you need to be careful about is creating QObjects in different thread contexts. If you create a QObject in a secondary thread you either destroy it before the thread ends or you move it to another thread, e.g. the application's main thread.

If you protect your property getters and setters with mutexes you can have a QObject in a secondary thread and use it from QML.
You can alternatively have the interface object live in the main thread and implement some of its methods in a way that they delegete to a thread.

You mentioned earlier that you had external processes instead of threads in a different implementation. You could still use that here as another alternative.

Cheers,
_

PascalSevran
6th May 2014, 11:53
Thanks a lot for your answers, I'll try to figure out how to deal with my threads based on what you said.

As far as splitting the requester and the replier onto 2 external processes, I really dont see how I could launch them from a GUI button click since they need to be running in paralel :s

anda_skoa
6th May 2014, 11:55
QProcess

Cheers,
_