PDA

View Full Version : QThread implementation for serial port monitoring



kpkale
10th July 2012, 13:30
I am writing a program for control of a machine using serial port. At one point, I am required to run a process on another thread. For implementing the same I am following the tutorial given here.
http://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/


My application is a GUI based application. The serial port and its functions are being handled by a separate class which has a port object (using qextserialport library). This port object is opened and closed at the start and ending of the application.
Here, when I press one button on the FORM, I require to start a thread that will monitor the serial port for a particular input and execute a slot when the input is recieved from the serial port.
Following is excerpts from the code written when the button is pressed.

QThread* thread = new QThread;

ports->moveToThread(thread);

connect(thread, SIGNAL(started()), ports, SLOT(start()));

connect(ports, SIGNAL(dataFound(QString)),this, SLOT(ondatafound(QString)));

connect(ports, SIGNAL(finished()), thread, SLOT(quits()));


connect(ports, SIGNAL(finished()), ports, SLOT(deleteLater()));

connect(ports, SIGNAL(finished()), thread, SLOT(deleteLater()));

thread->start();
Here, the ports (Worker) class is the class which is controlling all the functions related to the serial port.
Here, the start slot executes a Qtimer that reads the serial port after a timeout till the required data is not received. And after receiving data, emits the datafound signal and also emits the finished signal.



This works for one time execution. However, when I press the Button again for re-executing which I am required to do again and again, after the ondatafound slot is executed, The QT gives an error and does not execute the movetothread.


What I see in the tutorial is that a new instance of the worker class is created and movetothread is called and I am not doing it that way... but dont know the right way of doing it either for the thing to work.

Secondly, I also need to have a provision of terminating this thread from the main thread in case I do not receive the data. So if i dont include the data from the serial port, then i need to push another button and continue the process further. I dont know how to terminate this thread from the main thread.

high_flyer
10th July 2012, 13:41
Please use the code tags instead of coloring your code text.
The code tags will color the code for you and will make it possible for others to copy and paste the code in their posts when they answer you.


the QT gives an error and does not execute the movetothread.
What error do you get?


I dont know how to terminate this thread from the main thread.
Did you consult QThread documentation for that?
Its exactly like starting the thread - with the exception, that you have to make sure in your thread, that it shuts down nicely and not leave stuff "half backed".

amleto
10th July 2012, 17:14
argh! time wasting cross forum poster
http://www.qtforum.org/article/38210/problem-in-implementing-multithreading.html:mad:

kpkale
11th July 2012, 08:02
OK... thanks for your comments and kind consideration.

I am attaching the testing code along with this post.
Also, I am attaching the screenshot which shows two things... Right side bottom, the program window shows the message I recieve from the machine when I send the command for the first time. For sending the command, first I have to press the CONNECT button to open the port. Then I just go to the LineEdit and press ENTER key.. you can see the code.
When I press the ENTER key again, I get the error which is seen in the screenshot at the center. This error is seen at line no. 64 which is movetothread line..

I think with this data, it should be simpler to understand the problem.
7992 & 7993

amleto
11th July 2012, 08:35
Still you havent shown any (useful) code... Your pic only shows seg fault, you don't mention any code line.

Did you just attach a binary file? Err, no-one in their right mind is going to run that outside of a vm/sandbox.

high_flyer
11th July 2012, 10:36
I think with this data, it should be simpler to understand the problem.
Its not.
http://www.catb.org/~esr/faqs/smart-questions.html#symptoms

kpkale
11th July 2012, 10:53
Sorry... the example program somehow got corrupted... trying to attach a zip file again so that you can download the example and see the complete code.

7996

And Now I have verified that the zip file is getting downloaded properly and you can browse the contents.

Thanks for your replies...

high_flyer
11th July 2012, 10:55
However, when I press the Button again for re-executing which I am required to do again and again, after the ondatafound slot is executed, The QT gives an error and does not execute the movetothread.
Show the slot connected to your button clicked() signal.
No, I don't have the time to install your project and debug it.

kpkale
11th July 2012, 11:02
that article is simply superb... thanks for that information. I am trying to assimilate and absorb the same..

OK

Here is the code

The ports is defined public for this class as I need to use the same for other work related to the serial port.


PortListener* ports = new PortListener;



void MainWindow::on_lineEdit_returnPressed()
{
QThread* thread = new QThread;
ports->moveToThread(thread);
connect(thread, SIGNAL(started()), ports, SLOT(start()));
connect(ports, SIGNAL(dataFound(QString)),this, SLOT(ondatafound(QString)));
connect(ports, SIGNAL(finished()), thread, SLOT(quits()));
connect(ports, SIGNAL(finished()), ports, SLOT(deleteLater()));
connect(ports, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
}

wysota
11th July 2012, 12:20
Based on the last snippet I can assume you have a member variable called "ports" but then you create a local variable (in first snippet of your last post) that shadows the member variable and you assign a new instance of PortListener to that, so your member variable remains invalid when you access it in line #4.

high_flyer
11th July 2012, 12:58
In addition to what wysota said:
Its not clear how and when your thread gets destroyed.
So it could be well that you have multiple threads running, all working on the same 'ports' object (in case you are not shadowing it the way wysota said) which can lead to undefined behavior when two treads are trying to do something with 'ports'.

But why do you use threads and not a QTimer?

amleto
11th July 2012, 13:49
connect(ports, SIGNAL(finished()), ports, SLOT(deleteLater()));


and then you try and use it later... of course it is deleted.


By the way, using QTimer and PortListener as globals like you do is pretty poor practice.


argh! time wasting cross forum poster
http://www.qtforum.org/article/38210/problem-in-implementing-multithreading.html:mad:

I still believe this will solve your problem.

kpkale
11th July 2012, 14:51
SOLVED !!!

Based on the comments by wysota, I could understand that the ports class was getting destroyed in the process of calling this thread. Hence it worked only once and then for the next time it gave me that error.
Implemented a separate class which calls the respective slots from the ports object and executes it and it worked.

Thanks all of you for your kind help.

amleto
11th July 2012, 15:25
Based on the last snippet I can assume you have a member variable called "ports" but then you create a local variable (in first snippet of your last post) that shadows the member variable and you assign a new instance of PortListener to that, so your member variable remains invalid when you access it in line #4.

ports is a global in that compilation unit