C++. Удалён объект в то время как он был блокирован (sleep) и сегфолт по выходу (QtConcurrent::run, в нём QThread::sleep)

Модератор: Модераторы разделов

FlySnake
Сообщения: 992
ОС: openSUSE

C++. Удалён объект в то время как он был блокирован (sleep) и сегфолт по выходу

Сообщение FlySnake »

Всем привет
Ситуация: есть объект, который внутри имеет функцию выполняющую сетевые операции. В ней есть sleep реализованный наследованием от QThread и использованием msleep функции. Запущено это всё в треде с помощью QtConcurrent::run Теперь мне нужно без шума и пыли удалить этот объект. Удаляю. Но "спящая" функция продолжает спать в треде. По истечению времени спячки она просыпается и как ни в чём ни бывало идёт дальше, но объект уже удалён и при попытке доступа к членам класса происходит сегфолт. Можно придумать несколько вариантов (расстановка флагов + ручной delete в нужное время вместо умных указателей), но ни один из них мне не нравится. Может быть можно как-то убить спящий тред при удалении объекта, в котором запущена блокирующая функция? Или выйти из функции сразу после просыпания если объект был удалён?
Спасибо сказали:
Аватара пользователя
Женя Подсыпальников
Сообщения: 482

Re: C++. Удалён объект в то время как он был блокирован (sleep) и сегфолт по выходу

Сообщение Женя Подсыпальников »

FlySnake писал(а):
19.03.2014 15:55
есть объект, который внутри имеет функцию

Обычно - ожидается, что породитель должен выступать и утилизатором,
вот почему деструктор родителя не должен бы возвращать, без возвращения функционального дитя.

Другое дело, что внешнему стирателю родителя может быть неудобным ждать,
и тогда это дело должно быть решено оповещением родителя о желании стирателя
и установкой, например, указателя в стирателе на родителя в нуль, чтобы не мочь касаться его боле.

Ну а родитель - да, может сказать функции, мол, хватит, и лишь потом, по возврату дитя, закончить собственный деструктор :)
Пойдём на рыбалку !
Спасибо сказали:
NickLion
Сообщения: 3408
Статус: аватар-невидимка
ОС: openSUSE Tumbleweed x86_64

Re: C++. Удалён объект в то время как он был блокирован (sleep) и сегфолт по выходу

Сообщение NickLion »

Не получится ли переделать код так, чтобы не было sleep'а, а была обработка сигналов? И посылать сигал на завершение объекту, а уже в слоте делать delete(Later).
Спасибо сказали:
FlySnake
Сообщения: 992
ОС: openSUSE

Re: C++. Удалён объект в то время как он был блокирован (sleep) и сегфолт по выходу

Сообщение FlySnake »

Пока придумал такое решение. Вместо QThread::sleep использую QEventLoop с таймером:

Код: Выделить всё

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) и сегфолт по выходу

Сообщение FlySnake »

Вроде разобрался. Надо reply->abort() вызывать не напрямую в деструкторе, а эмитить сигнал, который подключается к этому слоту abort().
Спасибо сказали:
Аватара пользователя
Женя Подсыпальников
Сообщения: 482

Re: C++. Удалён объект в то время как он был блокирован (sleep) и сегфолт по выходу

Сообщение Женя Подсыпальников »

Как только некоторый ресурс делится опромеж потоков -
сразу хорошо вспоминать про замки на него, как то критические секции и мьютексы.

По мне - деструктор бракован,
если возвращает, не освободив выделенную объектом память или не завершив всех его потоков.

По Вашему коду я не смог увидеть, кто кому хозяин,
однако, сомнение о чистоте деструктора закралось :)
Пойдём на рыбалку !
Спасибо сказали:
FlySnake
Сообщения: 992
ОС: openSUSE

Re: C++. Удалён объект в то время как он был блокирован (sleep) и сегфолт по выходу

Сообщение FlySnake »

Условно говоря есть 2 класса. Первый рождает второго, который делает грязную работу с сетью. Оба создаются в одном потоке. Первый рождает его в QSharedPointer и хранит его. В деструкторе "родителя" на этом шаред поинтере "рождённого" делается clear() который уменьшает refcount и т.к. больше этот умный указатель нигде не используетя, то и "рождённый" объект удаляет. В принципе сейчас ничто не мешает делать олдскульный new в конструкторе и delete в деструкторе "родителя", но мне это не нравится т.к. велика вероятность что "рождённый" объект может ещё где-то понадобиться и тут умный указатель станет реально полезен.

Сейчас же речь шла только про "рождённый" объект и проблемы внутри него. Т.е. мне по-любому нужно прервать сетевую операцию или sleep() в этом объекте по команде от пользователя. И тут не важно кто и когда удаляет этот объект. Я просто посчитал что красивее прерывать все его сетевые операции и слипы удалением объекта вместо проверки всяких флагов в цикле.

А с QNetworkReply видимо реально из-за доступа к reply из разных потоков происхоили траблы.
Спасибо сказали:
Аватара пользователя
Женя Подсыпальников
Сообщения: 482

Re: C++. Удалён объект в то время как он был блокирован (sleep) и сегфолт по выходу

Сообщение Женя Подсыпальников »

FlySnake писал(а):
20.03.2014 20:31
Я просто посчитал что красивее прерывать все его сетевые операции и слипы удалением объекта вместо проверки всяких флагов в цикле.

Т.е. в изначальном дизайне петель (потоковых циклов) объекта
не было предусмотрено выхода по желанию объекта,
ведь иначе это бы с удовольствием использовалось в его деструкторе :)

(Наверное, я бы отвёл класс потока с ссылочкою на родителя (потока),
по которой можно всегда спросить "Хошь - выйду прямо щас ?" в ответственных местах.
Технику "слип", наверное, заменил бы техникой "сигнала" ли "переменной условия"(condition variable) на подъём к работе ли выходу.
А разделённый опромеж потоков ресурс - наверное, предоставлял бы лишь по запору конкурентам, хоть и на удаление)

А то интересный оратор получается - тока-тока начал рот гутарить, мол, дамы и господа...
...и в самый этот момент, без прощаний - хлобысь себя по башке...
...а в кармане платочком - записка, мол, мой самосшитый пиджак со сцены не выносить, можа, кто наденет
Микрофон не упал - кто-то ещё держал его в руке, потихоньку насвистывая "коли хочешь быть здоров" :)
Пойдём на рыбалку !
Спасибо сказали: