Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

QtSerialPort instantiating in wrong thread, causing signals/slots to fail

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.

like image 868
Mike Trpcic Avatar asked Mar 01 '13 15:03

Mike Trpcic


2 Answers

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).

like image 66
miq Avatar answered Oct 15 '22 11:10

miq


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.

like image 43
Mike Trpcic Avatar answered Oct 15 '22 11:10

Mike Trpcic