Пока сделано так:
в обработчике closeEvent(QCloseEvent *) генерю сигнал для отработки всех необходимых действий.
Иногда это все работает, а иногда не успевают все необходимые действия выполниться (не пойму пока почему так).
Надо понять почему. Если используется только DirectConnection - проблем быть не должно. Если QueuedConnection в том же потоке, то его можно "протолкнуть" с помощью processEvents (см также hasPendingEvents). Вот если в др потоке - придется как-то организовать "ответ" что действие выполнено (или поток завершен).
В общем первое что стоит попробовать - после эмита сигнала вызвать processEvents
Решение - в closeEvent вызываем собственноручно написанный слот-функцию "quit". В котором мы проверяем, всё ли мы сделали.
Основная идея слот/сигнал "я испустил а кому надо разберется", что позволяет испускающему не знать разбирающихся. А если сами "все проверяем" - смысла в слот/сигнал никакого.