Добрый день. Создаю поток, наследуясь от QThread (на хабре статью читал, что так не надо). В потоке в методе run создают динамический объект. Как мне можно остановить этот поток, при этом что бы объект был удален и вызван метод объекта для закрытия ресурсов. Смотрел варианты когда в run крутится вечный цикл
while( !flStop ) {
//do work
}
но у меня все построено на событиях
MyThread::run() {
mSerial = new QSerialPort;
mSerial->open(); //вопрос что если не откроем, пока оставим
exec();
}
, приходят сигналы и вызываются соответствующие им методы объекта,
т.е. если я попадаю в метод потока где удаляю ресурсы
а mSerial уже удален, т.е. если я все правильно понимаю, метод
clear должен быть финальным и в нем необходимо себя останавливать, либо эмитить сигнал и заставлять другой объект останавливать MyThread, но если я заэмичу сигнал, то где гарантии, что мне не прилетит сигнал на запись в mSerial. Т.е. получается при таком подходе я должен в clear и тормозить сам себя методом quit(). Такой вот вопрос
Так и clear и write ведь обработчики событий, а значит выполнятся в одном и том же потоке — в потоке MyThread. А значит одно не начнется, пока другое не закончилось.
Ну да, пока кто-то не приконнектится к этому потоку не функой по умолчанию, хм. На каком нить уровне иеррархии, где даже не известно, что это поток. Нет уж, не должна инкапсулированая сущность зависеть от метода её вызова.
Ну да, пока кто-то не приконнектится к этому потоку не функой по умолчанию, хм. На каком нить уровне иеррархии, где даже не известно, что это поток
Этого не может быть, потому что быть не может. А ещё потому, что в реализации QThread таки написано в начале Q_OBJECT.
Но даже если бы Q_OBJECT там не было, известно что это наследник QObject (иначе ты попросту не приконнектишь). А дальше Qt обеспечит кьюинг обработчиков. А если коннектишь через std::bind или лямды, то ССЗБ.
Но даже если бы Qt не обеспечивал, то ТС нигде не говорил, что это вот все находится в публичном интерфейсе либы, а значит все места, где коннектится подконтрольны.
Нет уж, не должна инкапсулированая сущность зависеть от метода её вызова.
Если это пойдет на пользу производительности, то запросто может и зависеть. Параллелят всегда ради производительности и отзывчивости.
Но ты можешь на каждый чих лочить мутекс, ждать пока рак на горе свистнет и т.д. И будешь таким же спецом в параллельном программировании, каким был бы спецом в управлении памятью гипотетический чувак, завернувший абсолютно всё в std::shared_ptr, вместо стека, виков и уников. Безопасно, но не оптимально.
И алыверды, для тех кто боится мьютексов :) Можно посмотреть, что происходит при Auto соединении. Там как раз всегда проверяется какому потоку принадлежит объект(раз лок), если не текущему лочится обьект треда(два лок), если в нём запущен цикл обработки событий, то лочится его очередь(три лок) иначе вроде лочится главный цикл и сообщение попадает туда(точно не помню уже). А вот если в ручную тип соединения указать, можно немного сэкономить на спичках.
Кстати про Auto соединение, мне лень читать, но скорее всего, нужно ещё обьекту твоего потока сделать moveToThread, что бы всё работало, как ты задумываешь. Т.к. создаётся сам инстанс QThread в основном потоке. А вот мувит ли он сам себя - х3, я бы не стал например.
Можно посмотреть, что происходит при Auto соединении. Там как раз всегда проверяется какому потоку принадлежит объект(раз лок), если не текущему лочится обьект треда(два лок), если в нём запущен цикл обработки событий, то лочится его очередь(три лок) иначе вроде лочится главный цикл и сообщение попадает туда(точно не помню уже)
Это те расходы, которые ТС собрался нести.
но у меня все построено на событиях
Чтобы избавиться от них ему придётся переписать всё на QtConcurrent, или, на худой конец, переписать MyThread на бесконечный цикл. Если тебе интересно моё мнение, то да, это стоит сделать.
А вот если в ручную тип соединения указать, можно немного сэкономить на спичках.
Поэтому, я указываю. Но уж никак не Qt::DirectConnection, где автоматика бы выставила Qt::QueuedConnection. Qt::DirectConnection ставлю только тогда, когда точно знаю, что обработчик нужно выполнить в том же потоке, где заэмитился сигнал.
P.S. не нужно так сильно хейтить реентрабельность и везде насаживать полную тредсафе.
Это те расходы, которые решает нести или нет продвинутый пользователь api. Внутреннее оно или внешнее особой роли не играет с ростом проекта. А экономия на локе в современных(последние лет 10) системах - нужна только когда ты начала считать сотни наносекунд. Что в gui приложения огромная редкость (лично я ни разу не видел). Если драки на блокировке не происходит, то она стоит как пара разыменовываний указателей, особенно если мимо кэша.
Если тебе интересно моё мнение, то да, это стоит сделать.
Проделай, лучше когда нибудь упражнение - свой бесконечный цикл и QEventLoop и глянь у кого окажется трупут выше и лэйтенси ниже. Я бы со всеми накладными расходами поставил таки на кутишников, т.к. эта горячая точка годами оптимизируется не глупыми товарищами :)
А экономия на локе в современных(последние лет 10) системах - нужна только когда ты начала считать сотни наносекунд. Что в gui приложения огромная редкость (лично я ни разу не видел).
Ну давай, забей на сотни наносекунд в paintEvent-е своей кастомной, красивенькой в цветах твоего проекта/компании, кнопочки. Которых на всех формах всех окон сотни. Вангую, что с таким подходом ты вскоре придёшь к стойкому убеждению, что QPainter тормозит, и вообще с графикой в линухе полная габелла, нативная кроссплатформа мертва, Qt разжирел и не торт больше вовсе.
Считал я эти микросекунды. Одно дело когда какой нить софт риалтайм с 10г сетевухами, а другое дело когда ui поток без логики с самым распрекрасным opengl на борту спит 50% времени даже если пользователь бьётся в эпилептических припадках в обнимку с клавой и мышью.
Если что, моник моргает с частотами порядка миллисекунды.
Подвох в том, что непонятно когда можно удалять поток. Вот есть где-то объект которые владеет указателем на поток. Я так понимаю, что когда мы удалили ресурсы, остановили поток, можно эмитить сигнал, что теперь объект потока можно и удалить.
Ну, раз сосут ничего тут не поделаешь. Правда не очень мне понятно почему в коде, который соревнуется с циклом обработки сообщений не используется ни семафоров ни условных переменных, но наверное так можно.
Смотря в каком потоке вызывается MyThread::clear() - я предполагал, что она выполняется в самом потоке, тогда quit() приводит к выходу из QEventLoop и немедленному завершению главной функции потока
Я всю жизнь наследовался и дед мой от QThread наследовался. С какого хрена я там буду объектно-ориентированной парадигме прогибаться? Как сподручней в данном случае так и сделаю. Вообще мне нужны очень веские аргументы что бы не наследоваться (от хорошего к лучшему). Что касается рекомендуемого метода, мне его сложней осознавать и как следствие я выбрал что проще.