Всем привет
Ситуация: есть объект, который внутри имеет функцию выполняющую сетевые операции. В ней есть sleep реализованный наследованием от QThread и использованием msleep функции. Запущено это всё в треде с помощью QtConcurrent::run Теперь мне нужно без шума и пыли удалить этот объект. Удаляю. Но "спящая" функция продолжает спать в треде. По истечению времени спячки она просыпается и как ни в чём ни бывало идёт дальше, но объект уже удалён и при попытке доступа к членам класса происходит сегфолт. Можно придумать несколько вариантов (расстановка флагов + ручной delete в нужное время вместо умных указателей), но ни один из них мне не нравится. Может быть можно как-то убить спящий тред при удалении объекта, в котором запущена блокирующая функция? Или выйти из функции сразу после просыпания если объект был удалён?
C++. Удалён объект в то время как он был блокирован (sleep) и сегфолт по выходу (QtConcurrent::run, в нём QThread::sleep)
Модератор: Модераторы разделов
-
FlySnake
- Сообщения: 992
- ОС: openSUSE
-
Женя Подсыпальников
- Сообщения: 482
Re: C++. Удалён объект в то время как он был блокирован (sleep) и сегфолт по выходу
Обычно - ожидается, что породитель должен выступать и утилизатором,
вот почему деструктор родителя не должен бы возвращать, без возвращения функционального дитя.
Другое дело, что внешнему стирателю родителя может быть неудобным ждать,
и тогда это дело должно быть решено оповещением родителя о желании стирателя
и установкой, например, указателя в стирателе на родителя в нуль, чтобы не мочь касаться его боле.
Ну а родитель - да, может сказать функции, мол, хватит, и лишь потом, по возврату дитя, закончить собственный деструктор
Пойдём на рыбалку !
-
NickLion
- Сообщения: 3408
- Статус: аватар-невидимка
- ОС: openSUSE Tumbleweed x86_64
Re: C++. Удалён объект в то время как он был блокирован (sleep) и сегфолт по выходу
Не получится ли переделать код так, чтобы не было sleep'а, а была обработка сигналов? И посылать сигал на завершение объекту, а уже в слоте делать delete(Later).
-
FlySnake
- Сообщения: 992
- ОС: openSUSE
Re: C++. Удалён объект в то время как он был блокирован (sleep) и сегфолт по выходу
Пока придумал такое решение. Вместо QThread::sleep использую QEventLoop с таймером:
waitTimer - член класса. В деструкторе делаю waitTimer.stop(). Вроде работает
Сейчас другая проблема появилась.
В деструкторе так же есть:
где reply - это QNetworkReply * член класса.
В коде есть загрузка файла:
Так вот, если убить объект во время загрузки файла, то получаю сегфолт на QByteArray a = reply->readAll();
Если я правильно понимаю документацию, то reply->abort() должен прибить все сетевые операции. Но что происходит если в это время выполняется загрузка с помощью readAll и как корректно прервать эту загрузку?
Код: Выделить всё
void waitOnQEventLoop(quint32 msec)
{
waitTimer.setInterval(msec);
waitTimer.setSingleShot(true);
waitTimer.start();
QEventLoop loop;
QObject::connect(&waitTimer, SIGNAL(timeout()), &loop, SLOT(quit()));
loop.exec();
}waitTimer - член класса. В деструкторе делаю waitTimer.stop(). Вроде работает
Сейчас другая проблема появилась.
В деструкторе так же есть:
Код: Выделить всё
if(NULL != reply) {
reply->abort();
}где reply - это QNetworkReply * член класса.
В коде есть загрузка файла:
Код: Выделить всё
if(!file.open(QIODevice::WriteOnly)) {
...
}
QByteArray a = reply->readAll();
file.write(a);
file.close();Так вот, если убить объект во время загрузки файла, то получаю сегфолт на QByteArray a = reply->readAll();
Если я правильно понимаю документацию, то reply->abort() должен прибить все сетевые операции. Но что происходит если в это время выполняется загрузка с помощью readAll и как корректно прервать эту загрузку?
-
FlySnake
- Сообщения: 992
- ОС: openSUSE
Re: C++. Удалён объект в то время как он был блокирован (sleep) и сегфолт по выходу
Вроде разобрался. Надо reply->abort() вызывать не напрямую в деструкторе, а эмитить сигнал, который подключается к этому слоту abort().
-
Женя Подсыпальников
- Сообщения: 482
Re: C++. Удалён объект в то время как он был блокирован (sleep) и сегфолт по выходу
Как только некоторый ресурс делится опромеж потоков -
сразу хорошо вспоминать про замки на него, как то критические секции и мьютексы.
По мне - деструктор бракован,
если возвращает, не освободив выделенную объектом память или не завершив всех его потоков.
По Вашему коду я не смог увидеть, кто кому хозяин,
однако, сомнение о чистоте деструктора закралось
сразу хорошо вспоминать про замки на него, как то критические секции и мьютексы.
По мне - деструктор бракован,
если возвращает, не освободив выделенную объектом память или не завершив всех его потоков.
По Вашему коду я не смог увидеть, кто кому хозяин,
однако, сомнение о чистоте деструктора закралось
Пойдём на рыбалку !
-
FlySnake
- Сообщения: 992
- ОС: openSUSE
Re: C++. Удалён объект в то время как он был блокирован (sleep) и сегфолт по выходу
Условно говоря есть 2 класса. Первый рождает второго, который делает грязную работу с сетью. Оба создаются в одном потоке. Первый рождает его в QSharedPointer и хранит его. В деструкторе "родителя" на этом шаред поинтере "рождённого" делается clear() который уменьшает refcount и т.к. больше этот умный указатель нигде не используетя, то и "рождённый" объект удаляет. В принципе сейчас ничто не мешает делать олдскульный new в конструкторе и delete в деструкторе "родителя", но мне это не нравится т.к. велика вероятность что "рождённый" объект может ещё где-то понадобиться и тут умный указатель станет реально полезен.
Сейчас же речь шла только про "рождённый" объект и проблемы внутри него. Т.е. мне по-любому нужно прервать сетевую операцию или sleep() в этом объекте по команде от пользователя. И тут не важно кто и когда удаляет этот объект. Я просто посчитал что красивее прерывать все его сетевые операции и слипы удалением объекта вместо проверки всяких флагов в цикле.
А с QNetworkReply видимо реально из-за доступа к reply из разных потоков происхоили траблы.
Сейчас же речь шла только про "рождённый" объект и проблемы внутри него. Т.е. мне по-любому нужно прервать сетевую операцию или sleep() в этом объекте по команде от пользователя. И тут не важно кто и когда удаляет этот объект. Я просто посчитал что красивее прерывать все его сетевые операции и слипы удалением объекта вместо проверки всяких флагов в цикле.
А с QNetworkReply видимо реально из-за доступа к reply из разных потоков происхоили траблы.
-
Женя Подсыпальников
- Сообщения: 482
Re: C++. Удалён объект в то время как он был блокирован (sleep) и сегфолт по выходу
Т.е. в изначальном дизайне петель (потоковых циклов) объекта
не было предусмотрено выхода по желанию объекта,
ведь иначе это бы с удовольствием использовалось в его деструкторе
(Наверное, я бы отвёл класс потока с ссылочкою на родителя (потока),
по которой можно всегда спросить "Хошь - выйду прямо щас ?" в ответственных местах.
Технику "слип", наверное, заменил бы техникой "сигнала" ли "переменной условия"(condition variable) на подъём к работе ли выходу.
А разделённый опромеж потоков ресурс - наверное, предоставлял бы лишь по запору конкурентам, хоть и на удаление)
А то интересный оратор получается - тока-тока начал рот гутарить, мол, дамы и господа...
...и в самый этот момент, без прощаний - хлобысь себя по башке...
...а в кармане платочком - записка, мол, мой самосшитый пиджак со сцены не выносить, можа, кто наденет
Микрофон не упал - кто-то ещё держал его в руке, потихоньку насвистывая "коли хочешь быть здоров"
Пойдём на рыбалку !