PDA

View Full Version : Need Qt SerialPort class example using signals and slots WITHIN A THREAD



RolandHughes
10th December 2012, 19:38
I'm currently trying to use the SerialPort class which will be included as part of Qt 5 according to the Web site. Using it with 4.x on Ubuntu Linux. The examples are all kind of worthless. The documentation says the SerialPort class is thread safe, yet, SerialPort.h deliberately disables a copy constructor which makes it very difficult to do signalling. I have found many cheating examples which call waitForReadyRead() instead of doing it right.

Don't care about other libraries or other tools.

Looking actual compiling example of SerialPort class using signals and slots within a thread which is NOT the GUI thread.

Thanks,

wysota
10th December 2012, 20:03
The documentation says the SerialPort class is thread safe, yet, SerialPort.h deliberately disables a copy constructor
That's what each QObject-derived class does. It's perfectly normal.


which makes it very difficult to do signalling.
I don't see how signalling is related to copying.

RolandHughes
10th December 2012, 22:59
That's what each QObject-derived class does. It's perfectly normal.


I don't see how signalling is related to copying.

http://doc.qt.digia.com/4.6/qsignalspy.html#details
"Note: Non-standard data types need to be registered, using the qRegisterMetaType() function, before you can create a QSignalSpy."

http://doc.qt.digia.com/4.6/qmetatype.html#qRegisterMetaType
"Any class or struct that has a public default constructor, a public copy constructor and a public destructor can be registered."

prof.ebral
10th December 2012, 23:37
It is based off QIODevice, correct? Don''t the readyRead and readChannelFinished signals work?

wysota
10th December 2012, 23:42
http://doc.qt.digia.com/4.6/qsignalspy.html#details
"Note: Non-standard data types need to be registered, using the qRegisterMetaType() function, before you can create a QSignalSpy."

I assure you "QObject*" is more than standard. Furthermore, what do you need a signal spy for? It's for testing only and there is a fine example in the docs showing you how to use it.

Seeing where it leads to, I'll ask the ultimate question -- why would you want to pass a QObject instance as an argument to a signal? Do you do that with e.g. QCheckBox?

kuzulis
11th December 2012, 08:34
@RolandHughes

About what kind of class are you talking? If this class of addon QtSerialPort (http://qt-project.org/wiki/QtSerialPort), then:


...which will be included as part of Qt 5 according to the Web site.

This is not quite true. This class is an addon, but is not part of Qt! And most likely will not be as part of Qt, because it is the development of
custom developers, who do not have the time and resources to prepare and test the addon.

At the moment, in fact, the development is supported and is active only one developer.


The examples are all kind of worthless.

Wow? O_o What makes you think that they are useless?

This Open Source project, no one is obliged to write to you. Write yourself a useful example in
your opinion, and then I will maybe I add your example to trunk.


The documentation says the SerialPort class is thread safe, yet, SerialPort.h deliberately disables a copy constructor which makes it very difficult to do signalling.

Where is it written that it is "thread safe"? It is not so.


I have found many cheating examples which call waitForReadyRead() instead of doing it right.

Where cheating? In BlockingMaster/BlockingSlave? O_o


Looking actual compiling example of SerialPort class using signals and slots within a thread which is NOT the GUI thread.

In addition to the Terminal example, there are other examples of the use of signals / slots without using Threads.
Look here: https://codereview.qt-project.org/#change,41981

But they have not yet added to trunk.


Therefore, your conclusions are absolutely baseless and unconstructive.

b-s-a
11th December 2012, 09:09
RolandHughes, how to use SerialPort signals/slots from other thread:

//mythread.h
#include <QThread>
class MyThread : public QThread
{
Q_OBJECT
protected:
virtual void run();
};
//mythread.cpp
#include "mythread.h"
#include <QtAddOnSerialPort/serialport.h>
void MyThread::run()
{
SerialPort port; //do not set parent or read manual for QObject::moveToThread()!
//do some settings to port
//do some signals/slots connections
//do open the port
exec(); //run event loop
}

P.S.: this is standard way to use QObject derived objects with signals and slots from other thread.

wysota
11th December 2012, 10:58
Furthermore the question should be why to use a thread at all if one is going to use signals and slots instead of blocking waitFor* calls.

b-s-a
11th December 2012, 12:01
Furthermore the question should be why to use a thread at all if one is going to use signals and slots instead of blocking waitFor* calls.

Answer to this question should be very interesting. :)

RolandHughes
11th December 2012, 15:14
Answer to this question should be very interesting. :)

Why? Because there are many devices. You don't burn a thread using blocking waitFor calls when you have many, potentially many dozens, of devices communicating via serial, tcp/ip, digital, and other means. The GUI simply provides a control and reporting interface. Each device needs to be service by non-blocking threads so all devices can be service without data loss. To do this you need signals and slots to occur WITHIN THE THREAD, not the GUI thread. Later, once the entire application runs at low volumes with dynamic OS scheduling, one can add the thread scheduling specific to the CPU vendor so the GUI can run on one CPU and the devices can be evenly allocated across other CPUs. First, you have to get each device to live within a thread. University research centers, labs, and many other organizations have been redeveloping this basic application design for decades. It isn't new. It has been done in Assembly, Fortran, C, and a host of other languages over the years. This particular instance chose to use Qt for a front end so an attempt is being made to use Qt for all of it instead of a hodge-podge.

Beginner:
>>P.S.: this is standard way to use QObject derived objects with signals and slots from other thread.

Thanks for the code, but it has little to do with the issue. I'm very aware of how to do threads and get signals across them. The problem is that signals are not working WITHIN a thread for the Serial stuff...unless that "thread" happens to be the main GUI thread.

Kuzulis:

>>This is not quite true. This class is an addon, but is not part of Qt! And most likely will not be as part of Qt, because it is the development of
custom developers, who do not have the time and resources to prepare and test the ad

Then qtproject should change the wording at the top of this page:
http://qt-project.org/wiki/QtSerialPort

"The QtSerialPort module is an add-on for the Qt5 library, providing a single interface for both hardware and virtual serial ports.
Note: Also added support and for library Qt4."

>>Where cheating? In BlockingMaster/BlockingSlave? O_o
Cheating, not testing, whichever. Because there is no example using signals and slots within threads, it generally means there also is no unit test for the same. Burning a thread with blocking IO may be fine student type work which only has to run for 5 minutes while the instructor looks at it, but it isn't the kind of programming which should be taught, especially for the library which created the signals and slots concept.

>>In addition to the Terminal example, there are other examples of the use of signals / slots without using Threads.
Look here: https://codereview.qt-project.org/#change,41981

Once again, not what I'm looking for. Signals and slots always work well within the GUI thread. Where testing and development have habbitually been an issue is making signals and slots live within a thread which is not the GUI thread. The classes for handling TCP/IP do this splendidly. Other classes from other developers for device interface also work perfectly in their own little thread. Currently, the serial port works well outbound only. The readyRead() signal gets lost. I asked for someone to provide a working example because if there was an actual unit test for this the code would be readily available. Instead, I got a bunch of flak and attempts to cut corners.

wysota:

Given a signal is getting lost, QSignalSpy is the next step when one is on their own debugging a signal problem. Hopefully it will reveal a method of jimmying the connect()/signal map to get around this bug/issue.

kuzulis:
>>Therefore, your conclusions are absolutely baseless and unconstructive.

I assume you were looking in the mirror when you wrote that.


Ok. So, obviously, there is no unit test code out there launching a ReadWrite serial port in its own thread which can be verified by connecting with Putty or some other terminal emulator. In short, I'm on my own tracking this bug down and fixing it.

Lesiok
11th December 2012, 15:48
RolandHughes, just use QExtSerialPort. It is working in threads.

wysota
11th December 2012, 16:29
Why? Because there are many devices.
So?


You don't burn a thread using blocking waitFor calls when you have many, potentially many dozens, of devices communicating via serial, tcp/ip, digital, and other means.
You don't burn a thread when using signals and slots. Nobody says you should use waitFor*.


Each device needs to be service by non-blocking threads so all devices can be service without data loss.
What data loss? What are you talking about? Non-blocking threads? So if you want to handle say... 20 devices, you'd need 20 "non-blocking threads", thus you'd need at least 21 concurrent threads (assuming there are no other processes running in the system) thus at least 21 cores or processing units in your machine. Otherwise those threads will block because they have to share a limited number of processors.


To do this you need signals and slots to occur WITHIN THE THREAD, not the GUI thread.
No. Especially if, as you said yourself, GUI provides only an interface for controlling and reporting results. Unless you are running a really old machine (like 10 years old), a single thread will happily handle the UI and serial input.


Given a signal is getting lost
Signals can't be "getting lost". They are not socks falling under your washing machine. Qt's signal handling code is deterministic.

RolandHughes
11th December 2012, 17:34
RolandHughes, just use QExtSerialPort. It is working in threads.

That was my initial thought because I have used it before successfully, despite some quirks. That was before the requestor saw the wiki page which makes it sound like this new library is supposed to be part of Qt at some point. That, and there are persistent stories that QExtSerialPort isn't under development anymore. I may be forced to go back to that.

Thanks

Added after 21 minutes:

wysota,

Please stop replying to this thread. I do not know if it is a language barrier or what, but so far you haven't understood a single thing I've said. I thank you for your time.



You don't burn a thread when using signals and slots. Nobody says you should use waitFor*.
everyone who suggested the examples and unit tests were good "suggested" this since it is the only thing they used when not running in the GUI thread.




What data loss? What are you talking about? Non-blocking threads? So if you want to handle say... 20 devices, you'd need 20 "non-blocking threads", thus you'd need at least 21 concurrent threads (assuming there are no other processes running in the system) thus at least 21 cores or processing units in your machine. Otherwise those threads will block because they have to share a limited number of processors.

No. Aparently you have never done data acquisition. Your assumption is completely invalid. We do have multiple cores, but you do not need one per thread, especially for serial. I've run a 16 serial ports flat out (115200 baud at each port) on a sub Ghz processor without ever losing anything.


No. Especially if, as you said yourself, GUI provides only an interface for controlling and reporting results. Unless you are running a really old machine (like 10 years old), a single thread will happily handle the UI and serial input.

NOT EVEN CLOSE!

Tests left running over night or over the weekend generate millions of data points. Someone kicking off the GUI "report" to plot and graph outliers, or some other such "report" will bind that processor for minutes, if not hours. Don't compare this report to something you've done in school. Think SETI or some other serious research application where data points from a few minutes to a few days can completely fill a 1TB drive when stored in binary format. This is not two people chatting via some cheesey terminal.


Signals can't be "getting lost". They are not socks falling under your washing machine. Qt's signal handling code is deterministic.

Signals are dynamically mapped. Signals can easily get lost any time the entry in the signal map is missing or pointing to a null or pointing to an incorrect thread, hence why I was looking at the signal spy stuff as the next step.

Lesiok
11th December 2012, 17:37
QExtSerialPort IS developed. Here is QextSerialPort 1.2 RC (http://code.google.com/p/qextserialport/wiki/QextSerialPort_1_2_RC)

kuzulis
11th December 2012, 18:44
@RolandHughes

Mr. b-s-a showed for you how to use QtSerialPort object in non-gui threads, this is the basic concept when
need start Qt-event looping by call exec() method. Without Qt-event loop signals will not work.

Your statement that "lost signals" are totally groundless, you did not provide any simple code to reproduce this "problem".
All that you said - it's just empty words. No one will offer a turnkey solution for you, you must implement it yourself.



QExtSerialPort IS developed. Here is QextSerialPort 1.2 RC


QExtSerialPort does not provide fully asynchronous I/O on Windows, so you can lost productivity.
But in any case, if you consider yourself an expert, you can implement everything in WinAPI / POSIX themselves.


I repeat:
QtSerialPort - an Open Source project, if you do not like - you can fix it yourself or suggest a some solution,
or on end, do not use it, find another project.


After all, you're an "expert", but all around - "students"...bla-bla-bla

RolandHughes
11th December 2012, 20:20
kuzulis,



Your statement that "lost signals" are totally groundless, you did not provide any simple code to reproduce this "problem".
All that you said - it's just empty words. No one will offer a turnkey solution for you, you must implement it yourself.


Please learn just a tiny bit about a library before inserting your foot so far into your mouth. Signals are lost in most Qt applications and this is be design. When you use an object which emits signals do you assign a slot to catch each and every signal? No. You assign a slot to catch only the signal you are interested in. ALL THE OTHER SIGNALS EMITTED BY THE OBJECT ARE LOST. They have no entry in the dynamically created table matching signals to slots within and across threads. They are emitted and lost.

When new "projects" get added, sometimes they don't do things correctly when creating entries for non-GUI threads. When this happens, the signals emitted which do not have routing entries in the table are LOST. Rather than tossing errors and making developers catch each and every signal from each and every object, the Qt architecture allows developers to catch only those signals and it quietly LOSES the rest.



QExtSerialPort does not provide fully asynchronous I/O on Windows, so you can lost productivity.
But in any case, if you consider yourself an expert, you can implement everything in WinAPI / POSIX themselves.

Please re-read first message. This shop doesn't speak Windows. Development is occuring on Ubuntu Linux.

Students must learn to pay attention when gathering requirements so they don't develop something completely useless.

Thank you for your time.

wysota
11th December 2012, 21:01
everyone who suggested the examples and unit tests were good "suggested" this since it is the only thing they used when not running in the GUI thread.
I don't know who is "everyone" and what they "suggested", I'm not telling you to look at examples but to use QIODevice API like it is supposed to be used. You can search the Internet for similar discussions on doing networking with threads. "Everyone" "suggests" this is supposed to be done in threads because that's how they have been doing it using other technologies that didn't provide non-blocking API. It is not supposed to be done in threads.


Aparently you have never done data acquisition. Your assumption is completely invalid. We do have multiple cores, but you do not need one per thread, especially for serial. I've run a 16 serial ports flat out (115200 baud at each port) on a sub Ghz processor without ever losing anything.
Which is exactly my point. You don't need "non-blocking threads" (whatever you mean by that) to handle serial ports simply because the operating system will buffer data for you. If you are running 115200 baud transmission, it doesn't mean you need to read 115200 bits per second. It means you need to read 115200 per second on average. This is only 14kB per port, I'm sure single thread can handle reading 16 of these per second and still be able to do some fancy stuff in your UI.


Someone kicking off the GUI "report" to plot and graph outliers, or some other such "report" will bind that processor for minutes, if not hours.
Did it come to your mind to do this "minutes if not hours" lasting processing in a thread (or even in a separate process)? Are you really blocking your UI for "minutes if not hours" and still think that's ok? Are you sure it is me who never did any data aquisition and processing?


Don't compare this report to something you've done in school
We never did that in school because by the time I was finishing school we were running a single 56k modem shared by around 20 machines.


Think SETI or some other serious research application where data points from a few minutes to a few days can completely fill a 1TB drive when stored in binary format.
Oh jeez, and you want to process it in the GUI thread? That's so professional...


Signals are dynamically mapped. Signals can easily get lost any time the entry in the signal map is missing or pointing to a null or pointing to an incorrect thread, hence why I was looking at the signal spy stuff as the next step.

You have to be kidding. If you are worried about it and are unable to check if that is really the case then do proper synchronization in your code.

Stop trolling and claiming to have all the answers and start reading on proper usage of components at hand. Your post on disabled copy constructor in a QObject subclass clearly shows how well you understand Qt code.

Added after 6 minutes:


Please learn just a tiny bit about a library before inserting your foot so far into your mouth.
I think Kuzulis knows best of us how the QtSerialPort library works.


Signals are lost in most Qt applications and this is be design. When you use an object which emits signals do you assign a slot to catch each and every signal? No. You assign a slot to catch only the signal you are interested in. ALL THE OTHER SIGNALS EMITTED BY THE OBJECT ARE LOST.
So that's what you mean by a "lost" signal... I would rather call that "ignored".


They have no entry in the dynamically created table matching signals to slots within and across threads. They are emitted and lost.
Some of them might even not be emitted at all :)


When new "projects" get added, sometimes they don't do things correctly when creating entries for non-GUI threads. When this happens, the signals emitted which do not have routing entries in the table are LOST.
Are you talking about your own projects or projects in general?

prof.ebral
11th December 2012, 21:30
I'm still not 100% certain what you are looking for. From the initial post you want the QtSerialPort to process data while in a thread, and then the main program to handle that data while in a thread? Is that correct? If that is what you are looking for you might consider an MVC model where you model is your QtSerialPort classes and QThread classes, your View handles UI updates, and your Controller handles the signal connections. Your controller would accept emitted signals and start new threads to handle data processing.

As far as I understand data sent by signals is sent to the main thread. You are asking for this, "Looking actual compiling example of SerialPort class using signals and slots within a thread which is NOT the GUI thread."

wysota
11th December 2012, 21:38
As far as I understand data sent by signals is sent to the main thread.

There are two things here. "Data" (as in arguments to signals) are not sent to any thread, in the meaning that thread affinity of them does not change in any way. If you pass a pointer to a QObject that lives in thread A to thread B, then accessing that object there might cause data corruption or worse. If you pass some non-QObject by pointer then it doesn't have any thread affinity and it is its thread-safety that decides whether this is safe or not. if you pass a non-QObject by value then it is copied and in regular cases will have no notion of its other clone being accessed from the original thread. However another topic is if we interpret what you said as "signals are sent to the main thread" in which case this is not true -- signals are sent in the thread they are emitted in (it's just a plain function call) but connecting to them may cause an event to be posted to an object living in a different thread (it doesn't have to be the "main" thread though).

prof.ebral
11th December 2012, 21:44
However another topic is if we interpret what you said as "signals are sent to the main thread" in which case this is not true -- signals are sent in the thread they are emitted in (it's just a plain function call) but connecting to them may cause an event to be posted to an object living in a different thread (it doesn't have to be the "main" thread though).

Hmmm, I thought the main thread received the signal as a handler and then executed the method defined by the slot.

wysota
11th December 2012, 22:13
Hmmm, I thought the main thread received the signal as a handler and then executed the method defined by the slot.

No, it depends on the thread affinity of the object that the slot belongs to. Here is a simple example:


#include <QtCore>

class Object : public QObject {
Q_OBJECT
public:
Object(QObject *parent = 0) : QObject(parent) {

}
public slots:
void reportThread() {
qDebug() << Q_FUNC_INFO << QThread::currentThread();
}
};

#include "main.moc"

int main(int argc, char **argv) {
QCoreApplication app(argc, argv);

QVector<QThread*> threads;
QVector<Object*> objects;
for(int i=0;i<4;++i) {
QThread *thr = new QThread;
threads << thr;

Object *o = new Object;
o->moveToThread(thr);
objects << o;

thr->start();

}
// last object in main thread
objects << new Object;
qDebug() << "GUI thread:" << objects.last()->thread();
QTimer t;
t.start(2000);
foreach(Object *o, objects)
QObject::connect(&t, SIGNAL(timeout()), o, SLOT(reportThread()));
return app.exec();
}

You can also move the timer to one of the threads and see if it changes anything.

Oh, one more thing -- you can run this example under a debugger, set a breakpoint in the slot and look at the backtrace. You'll see how it differs for the last added object (the one that lives in the main thread) compared to other objects.

prof.ebral
11th December 2012, 22:33
Ok, thanks wysota. I use PyQt and when I look at the current thread inside a method that has been called by a signal it is the main thread. I've yet to see an instance when it is isn't in PyQt.

wysota
11th December 2012, 23:02
Ok, thanks wysota. I use PyQt and when I look at the current thread inside a method that has been called by a signal it is the main thread. I've yet to see an instance when it is isn't in PyQt.

Maybe you are using Python threads and not QThreads. I have no idea how Qt will behave then.

I ran this test program:

from PySide import QtCore
import sys

class Object(QtCore.QObject):
def reportThread(self):
print(QtCore.QThread.currentThread())

app = QtCore.QCoreApplication(sys.argv)
thr = QtCore.QThread()
obj = Object()

timer = QtCore.QTimer()
print("MainThread"+str(QtCore.QThread.currentThread()))
timer.timeout.connect(obj.reportThread)
timer.start(2000)
app.exec_()

and it behaves the same way as I described:

MainThread<PySide.QtCore.QThread object at 0xf6a050>
<PySide.QtCore.QThread object at 0xf6a0e0>
<PySide.QtCore.QThread object at 0xf6a0e0>

prof.ebral
11th December 2012, 23:06
This is the output I get


MainThread<PyQt4.QtCore.QThread object at 0x7f16ef83c408>
<PyQt4.QtCore.QThread object at 0x7f16ef83c408>

The main thread is located at the same memory allocation as all of the other threads.

edit: By the way, here is the changed code for PyQt


from PyQt4 import QtCore
import sys

class Object(QtCore.QObject):
def reportThread(self):
print(QtCore.QThread.currentThread())

app = QtCore.QCoreApplication(sys.argv)
thr = QtCore.QThread()
obj = Object()

timer = QtCore.QTimer()
print("MainThread"+str(QtCore.QThread.currentThread()))
timer.timeout.connect(obj.reportThread)
timer.start(2000)
app.exec_()
Not much different.

wysota
11th December 2012, 23:10
Maybe that's an issue with PyQt4 (I would rather suspect that it returns an incorrect thread pointer rather than runs the slot in a wrong thread). As you can see I was using PySide.


Edit: LOL... I forgot to move the object to the thread and start the thread ;)

Here is a working version:

from PyQt4 import QtCore
import sys

class Object(QtCore.QObject):
def __init__(self):
QtCore.QThread.__init__(self)

def reportThread(self):
print(QtCore.QThread.currentThreadId())

app = QtCore.QCoreApplication(sys.argv)
thr = QtCore.QThread()
obj = Object()
obj.moveToThread(thr)
thr.start()

timer = QtCore.QTimer()
print("MainThread"+str(QtCore.QThread.currentThreadId()))
timer.timeout.connect(obj.reportThread)
timer.start(2000)

t2 = QtCore.QTimer()
t2.timeout.connect(app.quit)
t2.start(10000)
app.exec_()

prof.ebral
11th December 2012, 23:13
Maybe that's an issue with PyQt4 (I would rather suspect that it returns an incorrect thread pointer rather than runs the slot in a wrong thread). As you can see I was using PySide.

I think it is a feature of PyQt. I'll have to check over the documentation again, but I think PyQt signals and slots operate 'through' the main thread. Like how I described before. Sorry for adding confusion to the post.

wysota
11th December 2012, 23:16
No, it's not a feature of PyQt. Look at my previous post, I just edited it.

prof.ebral
11th December 2012, 23:24
That doesn't work for me. I only receive the MainThread print statement in my terminal.

edit: wysota, here is some modified code and the output. Even after the Object class is moved to the Thread class I still get the main thread's ID ... but for me the signal is not being caught by the Object's reportThread method.



from PyQt4 import QtCore
import sys, time

class Object(QtCore.QObject):
def __init__(self):
QtCore.QObject.__init__(self)

def reportThread(self):
print self, (QtCore.QThread.currentThreadId())

class Thread(QtCore.QThread):
def __init__(self):
QtCore.QThread.__init__(self)

def reportThread(self):
print self, (QtCore.QThread.currentThreadId())

app = QtCore.QCoreApplication(sys.argv)
thr = Thread()
obj = Object()
obj.moveToThread(thr)
print obj, obj.thread(), obj.thread().currentThreadId()
thr.start()

timer = QtCore.QTimer()
print ( "MainThread "+str(QtCore.QThread.currentThreadId()) )
timer.timeout.connect(obj.reportThread)
timer.timeout.connect(thr.reportThread)
timer.start(2000)

t2 = QtCore.QTimer()
t2.timeout.connect(app.quit)
t2.start(10000)
app.exec_()

output:


<__main__.Object object at 0xabd2f8> <__main__.Thread object at 0xabd270> 140273089054464 MainThread 140273089054464
<__main__.Thread object at 0xabd270> 140273089054464
<__main__.Thread object at 0xabd270> 140273089054464
<__main__.Thread object at 0xabd270> 140273089054464
<__main__.Thread object at 0xabd270> 140273089054464
<__main__.Thread object at 0xabd270> 140273089054464

RolandHughes
12th December 2012, 14:59
I don't know who is "everyone" and what they "suggested", I'm not telling you to look at examples but to use QIODevice API like it is supposed to be used. You can search the Internet for similar discussions on doing networking with threads. "Everyone" "suggests" this is supposed to be done in threads because that's how they have been doing it using other technologies that didn't provide non-blocking API. It is not supposed to be done in threads.

Yes it is. Please do not try to view this application in terms of something running on a machine where the user can also surf the Web and check email.



Which is exactly my point. You don't need "non-blocking threads" (whatever you mean by that) to handle serial ports simply because the operating system will buffer data for you. If you are running 115200 baud transmission, it doesn't mean you need to read 115200 bits per second. It means you need to read 115200 per second on average. This is only 14kB per port, I'm sure single thread can handle reading 16 of these per second and still be able to do some fancy stuff in your UI.
That is very poor design and not allowed in a scientific environment were loss of a single data point scraps the entire test run.


Did it come to your mind to do this "minutes if not hours" lasting processing in a thread (or even in a separate process)? Are you really blocking your UI for "minutes if not hours" and still think that's ok? Are you sure it is me who never did any data aquisition and processing?

Oh jeez, and you want to process it in the GUI thread? That's so professional...

It is a design requirement. Do not confuse this with some application on a machine which has any other purpose or ability in life. The really large data sets can and do get off-loaded to serious computers for detailed analysis. The initial analysis to weed out non-interesting data sets occurs on the collection machine. What you consider a waste saves weeks and in some cases months of serious computing time.


You have to be kidding. If you are worried about it and are unable to check if that is really the case then do proper synchronization in your code.

Stop trolling and claiming to have all the answers and start reading on proper usage of components at hand. Your post on disabled copy constructor in a QObject subclass clearly shows how well you understand Qt code.

I'm not trolling or claiming to have all of the answers. I came in asking if there was unit test code proving this works. I got a bunch of responses which sounded like a Bing commercial.

My next debugging course was to use the signal tool, but any class which does not have a copy constructor cannot be used with it...a point you have repeatedly failed to recognize.

Please don't view this as a user application. This is a single purpose system running in an environment were no data point can be lost. Every device must be service by a non-blocking thread and those threads must be distributed across processors. It is not an end user application nor a hokey little smart phone app. It gathers all data points and the GUI only has two purposes. 1) Configure everything for a test run 2) run the reports/graphs used to identify interesting data sets. That's it.




Some of them might even not be emitted at all :)
Hence the wish to test with the signal tool.




Are you talking about your own projects or projects in general?
Projects which get released for use with Qt. I find they only provide unit test code/examples for GUI use, and nothing for use within non-GUI threads.

At any rate. This message thread can now end. I'm on my own fixing it or I have to switch to qextserial.

Added after 7 minutes:


As far as I understand data sent by signals is sent to the main thread. You are asking for this, "Looking actual compiling example of SerialPort class using signals and slots within a thread which is NOT the GUI thread."

http://doc.qt.digia.com/qt/threads-qobject.html#signals-and-slots-across-threads

Queued Connection 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.

wysota
12th December 2012, 21:12
That doesn't work for me. I only receive the MainThread print statement in my terminal.

edit: wysota, here is some modified code and the output. Even after the Object class is moved to the Thread class I still get the main thread's ID ...
That's because the Thread object lives in the main thread. You only moved the Object instance to the thread, not the Thread instance. There is a distinction between a thread (as in a separate processing flow) and QThread instance.

prof.ebral
12th December 2012, 21:17
That's because the Thread object lives in the main thread. You only moved the Object instance to the thread, not the Thread instance. There is a distinction between a thread (as in a separate processing flow) and QThread instance.

>____< I used the code you gave me. "I" did not do that. Anyway, thank you.

wysota
12th December 2012, 21:36
Yes it is. Please do not try to view this application in terms of something running on a machine where the user can also surf the Web and check email.
And how is that related to anything we've been discussing about? I don't care where the application runs. I care that a single thread doesn't have any problems in reading data from multiple sockets/ports.


That is very poor design and not allowed in a scientific environment were loss of a single data point scraps the entire test run.
What is poor design and how does having another thread prevent loss of some data that would otherwise magically be lost? Data is not lost if you read it 10ms later or 20ms later or even 2 seconds later. It's still there. What matters is that you read data fast enough to prevent cluttering the input buffer. And even that is nothing wrong if you are using TCP as the protocol itself is designed to prevent any data loss. Your serial port doesn't have that safety mechanism and thus you need to pay attention to read the data fast enough to not overrun the input buffer for the port. But it totally doesn't matter which thread performs the read.


It is a design requirement. Do not confuse this with some application on a machine which has any other purpose or ability in life.
Strange. Somehow your flaws are "by design" (yeah yeah, it's a feature, not a bug) and something you consider a "flaw" in others' thinking is "unserious school project". Be serious. Any unresponsive system is badly designed. Period.


I'm not trolling or claiming to have all of the answers. I came in asking if there was unit test code proving this works. I got a bunch of responses which sounded like a Bing commercial.
Yes, you are trolling. Just read your posts.


a point you have repeatedly failed to recognize.
So... QPushButton is also badly designed because it also has a disabled copy constructor? What about QSignalSpy itself? It also has a disabled copy constructor. So does every QObject-derived class. And so does QtSerialPort which is a sign of good design on behalf of its author.


Please don't view this as a user application. This is a single purpose system running in an environment were no data point can be lost.
I'm sorry but as a user of any user application I would not like to have any of my data lost too. And as a programmer of such applications I wouldn't want to have any data lost. Your system is by no means special.


Hence the wish to test with the signal tool.
If you test with the signal tool, the signal will be emitted because the connection from the tool will make its emitter emit it. I think you fail to understand what I meant. Read the docs for QObject::receivers() to see what I meant and how does QSignalSpy influence it.


Projects which get released for use with Qt.
No. My projects never loose any signals, they don't loose any "data points" nor anything like that. They often use multithreading and classes from them are often thread-safe. So please talk about your projects, not about others'.


This message thread can now end.
Thank you, your Grace, for giving us your permission :)


>____< I used the code you gave me. "I" did not do that. Anyway, thank you.

You subclassed QThread. I didn't.

prof.ebral
13th December 2012, 19:43
You subclassed QThread. I didn't.

I used the original code, then modified the code to show the thread Id. The original code did not work for me. I posted that. This conversation between you and me is of no value, and you seem to have a problem reading.

wysota
13th December 2012, 21:12
Look, the essential difference between code from posts #25 (mine) and #28 (yours) is that the code in post #28 subclasses QThread and connects to a slot from an instance of this class (lines 11-16 and 28). This is why you get the id of the main thread --- because QThread instance lives in the main thread. If you always do that in your code (meaning you connect a signal to a slot in the QThread subclass) then indeed all slots are executed in the context of the main thread, because that's where the QThread subclass instance lives. The modification you did in post #28 to my code from post #25 is what makes the difference between your output and mine.

prof.ebral
13th December 2012, 22:18
Wysota ... the Object doesn't even execute the reportThread method in your code, nor in mine. I'm trying to point that out to you. Like I said, you have a hard time reading.

Here ... I will quote my post:
"That doesn't work for me. I only receive the MainThread print statement in my terminal.

edit: wysota, here is some modified code and the output. Even after the Object class is moved to the Thread class I still get the main thread's ID ... but for me the signal is not being caught by the Object's reportThread method."

wysota
13th December 2012, 23:55
Wysota ... the Object doesn't even execute the reportThread method in your code, nor in mine. I'm trying to point that out to you. Like I said, you have a hard time reading.
I understand that it doesn't work for you, I don't know why. It works for me just fine and I'm sure it works for many other people because it is intended to work that way.


Even after the Object class is moved to the Thread class I still get the main thread's ID ... but for me the signal is not being caught by the Object's reportThread method."

You get the main thread ID's because you connect the timer's signal to the slot of an object that lives in main thread.

I just tried running the code you posted but it bails out with a syntax error (I'm using Python 3):

File "./code.py", line 11
print self, (QtCore.QThread.currentThreadId())
^


After fixing those syntax errors (by putting print arguments in parenthesis) and running the code, I get this:

<__main__.Object object at 0x7fa7c3b50b00> <__main__.Thread object at 0x7fa7c3b50a70> 140358524008192
MainThread 140358524008192
<__main__.Thread object at 0x7fa7c3b50a70> 140358524008192
<__main__.Object object at 0x7fa7c3b50b00> 140358466680576
<__main__.Thread object at 0x7fa7c3b50a70> 140358524008192
<__main__.Object object at 0x7fa7c3b50b00> 140358466680576

You can see two slots are called -- one in Object (with thread id 576) and the other one in Thread (with thread id 192). That's the correct behaviour as described in Qt docs (PyQt can't possibly work differently because it's just a wrapper over Qt C++ classes). I don't know why you're getting no output for Object, the most obvious reason is that the worker thread is not started (or its event loop is not running).

A side note: I checked with Python2.7 and it works the same way as with Python3:
(<__main__.Object object at 0x7fa08aaf7d40>, <__main__.Thread object at 0x7fa08aaf7cb0>, 140327479097088L)
MainThread 140327479097088
(<__main__.Thread object at 0x7fa08aaf7cb0>, 140327479097088L(<__main__.Object object at 0x7fa08aaf7d40>, 140327422002944L)
)
(<__main__.Thread object at 0x7fa08aaf7cb0>, 140327479097088L)
(<__main__.Object object at 0x7fa08aaf7d40>, 140327422002944L)
(<__main__.Thread object at 0x7fa08aaf7cb0>, 140327479097088L)
(<__main__.Object object at 0x7fa08aaf7d40>, 140327422002944L)

prof.ebral
14th December 2012, 02:28
You can see two slots are called -- one in Object (with thread id 576) and the other one in Thread (with thread id 192). That's the correct behaviour as described in Qt docs (PyQt can't possibly work differently because it's just a wrapper over Qt C++ classes). I don't know why you're getting no output for Object, the most obvious reason is that the worker thread is not started (or its event loop is not running).

That is why I subclassed it. The thread starts. You can modify the run or start methods and determine that if you want. I don't know why either.

wysota
14th December 2012, 10:50
The thread starts.
How do you know that? There is no code in your program that verifies if the thread is running.