Signals and slots does not work without an event loop.
That's correct.

The serial port read/write has to be done before the QApplication event loop.
This probably can't be done if the serial port class depends on a running event loop. QTimer won't work without an event loop either.

I am sure what you want to do can be done after the event loop is started. If what you are trying to do is to perform the serial port setup before the main GUI becomes visible, that is certainly possible. Instead of calling mainWindow.show() just before the call to app.exec() in main(), define a different MainWindow slot that will handle your setup. Call that slot from main() instead. As soon as the event loop starts (app.exec()), that slot will be called. Do your setup in there. Define a signal for MainWindow that gets emitted after the setup is done, and connect that signal to the QMainWindow::show() slot.