И пытаться как-то определить что поле QObjectPrivate * испорчено (ну хотя бы нечетный адрес). Придется подключить приватные хедеры.
Теперь, кажется, понятно - ловить событие от sender`а в receiver`а. Но что мы поймаем, если приемник уже разрушен? В том то и проблема, что мы цепочкой сигнал/слот можем управлять только со стороны объекта, который отправляет событие. А на стороне приемника мы не можем ничего сделать. Если бы соединение сигнал/слот мы бы могли отключать со стороны приемника, проблем бы не возникало.
Что-то подсказывает мне, что archiving никогда не удалится), цикл обработки событий уже не работает.
Удалится. Цикл в main еще работает в то время, как останавливаются потоки. Там у меня работает QtService, а вся программа выполнена в виде процесса.
Не поленился, проверил - деструктор archiving срабатывает (впрочем, я это и раньше проверял, просто убедился еще раз).
Конечно, хотелось бы увидеть весь проект или тестовый пример, или хотя бы стек вызовов по всем потокам.
Увы, сам проект ~50 тыс. строк, сделать минимальный пример - нехилая работа.
Но это уже и не требуется - проблему я локализовал. И она, как сразу мне подсказывали, в том, что "что receiver не живой".
Но пока не решил, что с этим делать.
В двух словах о проблеме, чтобы не было такого: "всем спасибо, все свободны"
.
У меня в составе ядра системы есть программные компоненты, отвечающие за взаимодействие с периферийными устройствами через аппаратные интерфейсы (usb, uart, i2c, ethernet и т.д.). В их задачу входит получение запросов от сервиса опроса или других, его преобразование в соответствии с прикладным протоколом (modbus, can, mqtt и т.д.) в raw-данные, передача в шину и получение ответа устройств. Что-то типа драйверов, я называю их контроллерами интерфейсов. Уверен, вы найдете более правильное название))
Крах программы наблюдается, когда я перед загрузкой новой конфигурации удаляю старые объекты контроллеров, использующих протоколы modbus rtu по протоколу TCP/IP. Это мой компонент (QModbusRtuClient), я сделал его на основе уже имеющихся в составе qtserialbus, исходники я публиковал где-то здесь. Ключевые фрагменты кода (не существенные части я пропускаю, отмечено '...'):
C++ (Qt)
CModbusInterface::CModbusInterface(...) {
...
//
modbusDevice = new QModbusRtuClient(this);
...
}
CModbusInterface::~CModbusInterface(){
if (modbusDevice) {
modbusDevice->deleteLater();
}
}
Объект modbusDevice реализует формирование запросов, передачу в шину, получение ответов и обработку ошибок. Думаю, фрагменты кодов тут не нужны - они есть в документации qt. Главное в том, что в этом объекте есть TCP-сокет, сигналы которого обрабатываются в CModbusInterface.
При удалении старой конфигурации удаляются объекты CModbusInterface. Если на шине все хорошо, все устройства отвечают (время реакции от нескольких мс до нескольких десятков мс), то удаление modbusDevice проходит успешно.
Но если какое-нибудь устройство перестает отвечать, включается механизм таймаутов и повторов (ретрейнов) - это стандартное поведение компонетов modbus в qt. Т.е. если перед удалением контроллера мой запрос передан в шину, то он в modbusDevice болтается еще как минимум (1+numberOfRetries)*timeout - несколько секунд, после чего сокетом формируется сигнал ошибки и отправляется уже удаленному modbusDevice. И программа валится.
Изменить timeout и numberOfRetries перед удалением не удастся, т.к. они начинают действовать на следующий запрос, и никак не влияют на текущий.
Почему я особо отметил, что используется TCP-сокет: для последовательного порта в библиоеке используется QSerialPort::clear(QSerialPort::AllDirections), что, видимо, обеспечивает при удалении объекта очистку всех буферов и предотвращает формирование сигналов портом. По крайней мере, при работе через последовательные порты у меня программа не валится. Для сокета такой функции нет.
Как решить проблему? На вскидку есть пара вариантов: первый - отложенное удаление старой конфигурации, что-то вроде сборки мусора. Я так делал, мне не понравилось. Второй - не удалять старую конфигурацию, а ее изменять. Наверное, это вполне рабочий вариант, хотя и довольно нудный.
Вот теперь могу сказать: спасибо, коллеги, за помощь.