11

I'm using the QtSerialPort library to talk to a virtual COM port via USB. The COM port returns data and works properly when testing it with the example projects given with QtSerialPort, but fails when I run it as part of my project.

I inspected the instantiation chain and threads that lead up to the QtSerialPort being instantiated, and found something a little strange. The results are below.

main()
  MainWindow (Thread 0xbf8dbe0)        // Thread "A"
    HardwareManager (Thread 0xbf8dbe0) // Thread "A"
      QSerialPort (Thread 0xbfb95f0)   // Thread "B" !?

In my code, the main() function instantiates a MainWindow, which in turn instantiates a HardwareManager and stores it as a private variable. When the HardwareManager is instantiated, it also instantiates the QSerialPort instance so it can properly talk to the COM port.

However, you'll notice above the my QSerialPort is in a different thread than the parent object, as well as it's parent object (It's in Thread B, while both ancestors are in Thread A). I think this other thread is causing my Signals/Slots to fail. If I dumpObjectInfo, it lists my Signal/Slot as being set up, but the events never fire.

this->serial = new QSerialPort();
connect(this->serial, SIGNAL(readyRead()), this, SLOT(readSerialData());

Above is the code that I use to create the new serial port and connect it to the proper slot. The actual baud, parity, and data/stop bit configuration happens separately (and works properly, as tested in the example app provided by QtSerialPort).

Does anyone have any insight as to why this particular object (QSerialPort instance) is being instantiated in a different thread? I've tried "moveToThread" to switch the thread association, but nothing seems to work.

I've also made a post on the Qt Project Forums, but have had no useful responses yet.

Edit: The following is the relevant code in the call chain:

// main()
QApplication a(argc, argv)
MainWindow window = new MainWindow(); // [1]
MainWindow.show();
return a.exec();

// MainWindow::MainWindow() [1]
this->toolController = new QtToolController(this);
HardwareManager *manager = new HardwareManager(this->toolController); // [2]

// HardwareManager::HardwareManager() [2]
this->serial = new QSerialPort();
connect(this->serial, SIGNAL(readyRead()), this, SLOT(readSerialData()));

When a QSerialPort is ready to be read from (it has data to provide), it fires the readyRead signal (at least, it's supposed to). This signal fires properly in the Qt example projects, but I never get the signal in my application. I believe the reason I'm not getting the signal is because of these thread issues.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Mike Trpcic
  • 25,305
  • 8
  • 78
  • 114
  • 1
    I don't know how QT works, so just a wild guess: are you creating `QSerialPort` in response to some event? Any chance that event handler called in the context of different thread? –  Mar 01 '13 at 16:01
  • Nope. The QSerialPort instantiation is within the HardwareManager instantiation, which is in MainWindow instantiation, which is called in the main() method. At this point, there are no signals/slots/callbacks being used. – Mike Trpcic Mar 01 '13 at 16:05
  • I believe you should not bother about other thread, you should bother about not working signal/slots only. Show us your main, please. And provide some info about when slot should fire – ixSci Mar 01 '13 at 16:11
  • I'm **not** bothering with another thread, it's just doing that. I'll paste more code to show the call chain. – Mike Trpcic Mar 01 '13 at 16:21
  • Updated the code, it now shows the methods in my call chain. Nowhere do I instantiate my own thread, and nowhere do I explicitly move things to a thread. – Mike Trpcic Mar 01 '13 at 16:27
  • Have you tried the blocking alternative to test whether it works? – Min Lin Mar 01 '13 at 16:58
  • 1
    Seems like your app is loading two instances of Qt library. Is QtSerialPort placed in shared library? If it is try building your app in release mode and check if this problem still occurs. My wild gues is that you're building your app in debug mode (seems logic as you're still developing and testing your app) but you're linking to QExtSerialPort in release mode. QExtSerialPort library is loading release Qt libraries while your app is loading debug Qt libraries. – Kamil Klimek Mar 01 '13 at 17:58
  • I looked at the sources of QSerialPort, and it doesn't seem that it's using any threading code (except for WinCE, are you programming for WinCE?) so it's even more weird that there is a problem with threads. I don't think that it would behave this way even if (as suggested above) you were using two different versions of Qt - but just to be sure try to use some dependency chacking tool - you haven't mentioned a platform: for windows use http://www.dependencywalker.com/ , for other you probably already know one ;) – j_kubik Mar 04 '13 at 23:43

2 Answers2

2

You could use QueuedConnection for catching signals from a different thread.

connect(this->serial, SIGNAL(readyRead()), 
    this, SLOT(readSerialData()), Qt::QueuedConnection);

This way, the slot should be executed in your main thread's context once the control returns to it's event loop.

Also, this post seems to suggest that you should not set a parent for the QtSerialPort (propably because moveToThread doesn't work on QObjects with parents).

miq
  • 108
  • 1
  • 6
  • Adding the parameter Qt::QueuedConnection should not be necessary, since the default Qt::AutoConnection (I am using Qt 5, not sure about Qt 4) also handles connections between different threads correctly. – FourtyTwo Jan 04 '18 at 11:11
1

In the spirit of keeping answers available to anyone else who encounters this problem, the issue was related to Release/Debug builds. The QtSerialPort library had been built ONLY for my Release environment, and for whatever reason, when running my application in Debug mode would link to the Release QtSerialPort, and thread contexts would get lost.

To fix this, I ensured I had built the proper version of the library, and then ensured I linked to the right version for my environment.

Mike Trpcic
  • 25,305
  • 8
  • 78
  • 114