Название: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: kuzulis от Января 29, 2009, 13:22 Потоки, сигналы, слоты и потенциальные касяки связанные с этим?
Допустим ,например, в моем приложении имеется две "подсистемы" А и B. Эти подсистемы представляют собой два экземпляра классов, наследуемых от QThread. 1. Поток А в бесконечном цикле передает потоку В сигнал sgReadData(int i) о том что он хочет прочитать некие данные. 2.Поток В принял этот сигнал, выполнил свой слот и выдал потоку А сигнал о том, что данные готовы... 3. поток А принял от потока В сигнал о том что данные готовы и обновил у себя их (про защиту данных QList от потокобезопасности я опускаю речь :)., сейчас не это главное узнать! ) //---------- подсистема А Код: class A: public QThread //---------- подсистема B Код: class B: public QThread в приложении делаем так: Код: A *threadA = new(A); Вопрос: 1. корректно ли так реализовывать мою идею? (т.е не "захлебнутся" ли потоки (приложение) таким количеством данных) 2. Какие "косяки" могут вылезти? 3. что если в сигнале класса В sgDataReady, указать для данных не тип int а указатель на *int ? (хотя везде в ассистенте передают типы а не указатели!) Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: Rcus от Января 29, 2009, 13:48 Assistant -> Thread Support in Qt же.
1. Работать не будет, читайте ман (нужна петля обработки событий) 2. не обрабатывается команда завершения потока, возможно нарушение приоритетов (starvation) 3. А зачем? Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: ритт от Января 29, 2009, 13:51 > про защиту данных QList от потокобезопасности
каково, а? ) > A *threadA = new(A); > B *threadB = new(B); > connect(A, SIGNAL(sgReadData(int)), B, SLOT(slReadData(int))); тоже неплохо... в целом идея неверная. мб для отдельно взятого случая подобным образом будет и проще, но бесконечный emit sgReadData(j) - это что-то уже за гранью. как я понял из кода выше, списки в обоих тредах должны синхронизироваться (из В в А) - не проще ли использовать что-то вроде QSharedMemory? ну, или хотя бы посмотри QWaitCondition Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: pastor от Января 29, 2009, 14:01 2 kuzulis: Возми книгу Jasmin Blanchette, Mark Summerfield C++ GUI Programming with Qt 4 (существут перевод этой книги на русский) и прочти 14 раздел Multithreading.
Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: kuzulis от Января 29, 2009, 14:23 Цитировать 1. Работать не будет, читайте ман (нужна петля обработки событий) блина... читаю... ток голова пухнет! и что - то не могу понять!Цитировать 2. не обрабатывается команда завершения потока, возможно нарушение приоритетов (starvation) это я опустил дабы не загромождать код :)Цитировать 3. А зачем? ну, чтобы поток В прислал потоку А указатель на данные типа *int , т.к поток А тогда по этому указателю вычитает данные быстрее нежели из переменной ... типа для скорости :)Цитировать > про защиту данных QList от потокобезопасности да блина главное смысл понятен о чем я! :)каково, а? ) Цитировать тоже неплохо... что имеете ввиду?Цитировать в целом идея неверная. мб для отдельно взятого случая подобным образом будет и проще, но бесконечный emit sgReadData(j) - это что-то уже за гранью. ну мне нужно из подсистемы В в подсистему А бесконечно слать некие данные... в принципе я мог бы в бесконечном цикле потока А вызывать некую ф-ю типа B::readData(int i, int data) , предварительно объявив и реализовав ее в подсистеме В... но при этом придется включать #include "В.h" ...И вообще, в ассистенте написано, что сигналы и слоты для того еще введены, чтобы можно было стыковать объекты м/у собой, которые ничего не знают друг о друге :) (вот я и стыканул) Цитировать как я понял из кода выше, списки в обоих тредах должны синхронизироваться (из В в А) - не проще ли использовать что-то вроде QSharedMemory? ну, или хотя бы посмотри QWaitCondition нет, вы наверное неправильно поняли.... это я просто списки сюда всунул ... а реально дело так должно быть (в моем идеале :) ) 1. поток А шлет потоку В сигнал о том, что он хочет из внутреннего хранилища (которое находится в подсистеме В) из "ячейки" с идентификатором ID = 333 получить данные (реально данные могут быть любыми, но в примере это int) : sgReadData(333); 2. поток В принимает этот сигнал и у себя запускает слот slReadData(333); 3. в этом слоте происходит "декодирование" числа 333 (например им закодирован некий путь к объекту внутри подсистемы В в котором хранятся данные) 4. после раскодирования - в слоте происходит чтение этих данных из этого объекта и пусть прочитали число = 999; 5. после того как прочитали - в слоте класса В выдаем сигнал для подсистемы А типа по ссылке ID=333 прочитали данные 999 : sgDataReady(333,999) 6. подсистема А приняв этот сигнал, запускает слот slUpdateData(333, 999) и записывает эти данные 999 в свое внутреннее некое хранилище данных , у которого свои идентификаторы т.е листы - это просто типа массивов каких-то данных (в принципе я массивы мог бы всунуть) вот как мне нужно сделать!!! типа приложение состоять должно из нескольких подсистем А, В, С .. и т.п .. которые должны работать в своих потоках и общаться между собой (передавать/принимать данные) желательно только с помошью сигналов и слотов, раз уж придумали тролли этот механизм! фухх.. :) Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: kuzulis от Января 29, 2009, 14:24 Цитировать 2 kuzulis: Возми книгу Jasmin Blanchette, Mark Summerfield C++ GUI Programming with Qt 4 (существут перевод этой книги на русский) и прочти 14 раздел Multithreading. там нет того что мне нужно! там все не то! Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: ритт от Января 29, 2009, 14:38 Цитировать Цитировать 1. Работать не будет, читайте ман (нужна петля обработки событий) блина... читаю... ток голова пухнет! и что - то не могу понять!Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: kuzulis от Января 29, 2009, 14:43 Цитировать от чего там пухнуть? хочешь, чтобы в потоке вызывался сигнал - используй ивентлуп (exec() потоку либо собственный). а вечный цикл убрать. /* кстати, "while (1)" называется "forever" Улыбающийся */ Я не понял насчет евентлупа! Я запуталсо! :(Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: ритт от Января 29, 2009, 15:48 тогда задай себе вопрос: "а нужны ли вообще мне эти потоки?" :)
если ответ себе будет "да, нужны - без них никак", брось всё на время - отдохни, а затем начинай читать про потоки с самого начала... без понимания примитивов работы с потоками, того и гляди, получится приложение, "защищённое от потокобезопасности" :) в качестве альтернативы посмотри на QtConcurrent Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: kuzulis от Января 29, 2009, 16:10 да! нужны! :)
я с exec() не очень понял, т.к примеров нету! т.е если я в вместо A->start() напишу А->exec() - то запустится цикл обработки сообщений и следовательно можно не переопределять ф-ю run() ? Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: ритт от Января 29, 2009, 16:51 а ничего, что QThread::exec() защищённый (protected)?
Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: kuzulis от Января 29, 2009, 16:55 О_о.. башка не варит под конец дня...
Значит надо делать так? Код: void B::run а в main.c писать: B->start() ? так что-ли ? :) Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: Dendy от Января 29, 2009, 16:59 Именно. А завершить выолнение exec() с помощью вызова thread->quit() или thread->exit( myReturnCode ).
Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: ритт от Января 29, 2009, 17:18 Именно. А завершить выолнение exec() с помощью вызова thread->quit() или thread->exit( myReturnCode ). а ещё можно сделать так: Код и безопасно удалять через delete thread; :) либо Код и удалять через thread->stop(); :) Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: Dendy от Января 29, 2009, 17:29 2 Константин, вот шустрый, я уже почти написал как нужно правильно.
Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: ритт от Января 29, 2009, 17:44 дык, напиши :)
лишним не будет...а там, глядишь, и на статью для вики наберётся... Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: kuzulis от Января 29, 2009, 19:59 стоп! давайте тогда подитожим !
например я определяю класс как наследник QThread Код: class Z: public QThread теперь напишу то что я думаю как оно работает (на сей момент) + какие у меня непонятки :) Поправьте меня где неправ я! И напишите как работает! 1. после вызова из main Z->start() , функция run() начинает выполняться в другом потоке ! (т.е не в потоке main) Так?! 2. пока run() выполняется, у класса Z получаем статус: isRunning() и т.п! (т.е "выполняется")! Так?! 3. когда в функции run() выполняется вызов exec() - то разрешается цикл обработки сообщений! (т.е если после этого вызвать извне или изнутри класса слот slotFunc1() - то сигнал signal1() успешно сэмиттится!) Так? 4. если бы не было вызова exec() в теле функции run() - то при вызове слота действия бы выполнились, НО сигнал бы не сэммитился! Так? 5. после того как в теле функции run() вызвался exec() - то после exec() выполнятся ли действия (которые ниже exec() идут в ф-ции run() ) или выполнение run() остановится на exec() и будет висеть так пока не сделать Z->quit() ? 6. после завершения функции run() (допустим если прервать там цикл или если без цикла) - класс Z семиттит сигнал : finished ? Так? ---- 7. теперь вот что! если вызвать слот slotFunc1() извне класса Z или изнутри класса Z (но не из функции run()) - то содержимое слота slotFunc1() выполнится в потоке main или в том же потоке что и run() (т.е. не в main) ? 8. при вызове слота (только не из run()) и пока выполняются действия в слоте - то статус класса Z будет isRunning ? 9. при окончании выполнения слота slotFunc1() - сэемитится ли классом Z сигнал finished() ? 10. после выполнения в теле run() вызова exec() - статус класса всегда будет isRunning() ? 11. после выполнения Z->quit() класс Z сэемитит сигнал finished() и т.п ? Так? --------- вроде пока все непонятки что хочу узнать Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: ритт от Января 29, 2009, 20:12 1. да
2. да 3., 4. сигнализирование от петли событий не зависит - сигнализировать можно и без неё 5. код после exec() отработает только после останова потока 6. да 7. у тебя slotFunc1 НЕ слот. если вызвать slotFunc1 как функцию, она будет отрабатывать в вызывающем потоке. если вызвать slotFunc1 через событие, слот отработает в своём потоке (вызывающая точка находится в петле) 8. статус потока не зависит от вызовов слотов и т.п. 9. нет 10. до выхода из run() 11. да Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: Dendy от Января 29, 2009, 20:31 Кстати, такой код выполнится в главном потоке, а не в порождённом:
Код
В этом случае слот отработает прямо внутри emit mySignal(), а ну внутри Z::run(), так как экземпляр потока находится в том же потоке, в котором был выполнен connect(). Чтобы вызвать слот внутри Z::run() нужно коннектить так: Код
Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: ритт от Января 29, 2009, 20:42 точно? я не проверял код выше, но, помнится, по умолчанию для разных потоков используется Qt::QueuedConnection...и в таком случае слот как бы должен отрабатывать в своей петле...
Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: kuzulis от Января 29, 2009, 20:43 Цитировать 7. у тебя slotFunc1 НЕ слот. если вызвать slotFunc1 как функцию, она будет отрабатывать в вызывающем потоке. если вызвать slotFunc1 через событие, слот отработает в своём потоке (вызывающая точка находится в петле) это слот, просто я забыл написать: Код: public slots: Цитировать 3., 4. сигнализирование от петли событий не зависит - сигнализировать можно и без неё хм... а зачем тогда вообще вызывать exec() ?----- и еще: если я оставлю ф-ю run() пустой, то получается что после вызова Z->start() поток сразу завершится, выдаст сигнал finished() и, если я сделаю так : connect(this, SIGNAL(finished()), this, SLOT(deleteLater())); то получается что сразу после старта - класс Z сразу завершится и нафик удалится!!!! Ёлки! И я тогда никогда не смогу воспользоваться вызовом слота slotFunc1() , который например теоретически может быть привязан к сигналу, исходящему от какого нить класса Y ! :( Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: Dendy от Января 29, 2009, 21:08 точно? я не проверял код выше, но, помнится, по умолчанию для разных потоков используется Qt::QueuedConnection...и в таком случае слот как бы должен отрабатывать в своей петле... У вас хорошая память, всё так и есть - для разных потоков. Только экземпляр Z находится в том же потоке, что и эмиттер сигнала. Присмотритесь. Это типичная ошибка как новичков, так и более продвинутых программистов. Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: ритт от Января 29, 2009, 21:11 > хм... а зачем тогда вообще вызывать exec() ?
выше уже объясняли...раза два! у тебя слот в этом потоке. и тебе ведь нужно чтобы он работал. ----- не оставляй run() пустым. добавь в него exec(). Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: Dendy от Января 29, 2009, 21:12 хм... а зачем тогда вообще вызывать exec() ? Чтобы сработал ваш слот внутри exec(). Чтобы обьекты (QObject), созданные внутри run() получали события. если я оставлю ф-ю run() пустой, то получается что после вызова Z->start() поток сразу завершится ... и удалится Да. Другой вопрос с чего столько эмоций? Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: kuzulis от Января 30, 2009, 08:40 Доброго утра! :)
Подсскажите, а есть ли возможность узнать в каком потоке выполняется та или иная функция? т.е например что-то типа: ThreadId = getCurrentThreadId() ... это я к тому, чтобы мне можно было вывести в консоль ID-ы тех потоков, которых я хочу (для проверки фунциклирования) я не нашел в ассистенте ничего такого.. есть только: в описании QObject: QThread * QObject::thread () const - но это не ID (не дескриптор потока) в описании QThread: Qt::HANDLE currentThreadId () - вот это наверное то что нужно!!!? только непонятно что та зип данных HANDLE : --- Platform-specific handle type for system objects. This is equivalent to void * on Windows and Mac OS X, and embedded Linux, and to unsigned long on X11. Warning: Using this type is not portable. --- т.е это unsigned long ? ЗЫ: т.к все-равно у меня в голове еще все смутно и концы с концами не сходятся! Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: ритт от Января 30, 2009, 09:36 дебаж указатель на тред - тебе-то какая разница? что так циферя будет, что так...
Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: kuzulis от Января 30, 2009, 10:11 а поподробнее?
1. Куда и как ставить дебаж? 2. Как узнать ID потока главного приложения? (т.е main) Код: int main(int argc, char *argv[]) Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: kuzulis от Января 30, 2009, 10:28 написал код вот так:
Код: int main(int argc, char *argv[]) он мне показывает то что надо или нет ? о_О Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: ритт от Января 30, 2009, 11:49 Код покажет указатель и натив-ид главного треда. вот и сравнивай эти циферки в такими же циферками других тредофф. Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: kuzulis от Января 30, 2009, 12:49 в общем сделал я так:
классы: Код: class A : public QThread main Код: int main(int argc, char *argv[]) консоль мне выдала следующее: Цитировать Application -> TID = 0xe84 B::run() -> TID = 0x7e4 A::run() -> TID = 0xb98 B::slotB() -> TID = 0xe84 т.е слот slotB выполнился в потоке main с TID = 0xe84 , НО мне нужно чтобы он выполнился в потоке B с TID = 0x7e4 ! как это можно сделать? Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: kuzulis от Января 30, 2009, 13:29 но если пишу так:
объекты: Код: class A : public QObject main Код: int main(int argc, char *argv[]) то консоль выводит : Цитировать Application -> TID = 0x864 running ThA::run() -> TID = 0x11c running ThB::run() -> TID = 0x348 A::slotA() -> TID = 0x11c A::slotA() -> TID = 0x11c A::slotA() -> TID = 0x11c A::slotA() -> TID = 0x11c A::slotA() -> TID = 0x11c A::slotA() -> TID = 0x11c ^C т.е получается что не "ловится" или не емиттится сигнал A::sgFromA() слотом B::slotB() :( Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: kuzulis от Января 30, 2009, 15:20 вроде получилось :)
ab.h Код:
main.cpp Код: #include <QtCore> вывод: Цитировать Application -> TID = 0x830 running ThA::run() -> TID = 0xe4 running ThB::run() -> TID = 0x730 A::slotA() -> TID = 0xe4 A::slotA() -> TID = 0xe4 B::slotB() -> TID = 0x730 A::slotA() -> TID = 0xe4 B::slotB() -> TID = 0x730 A::slotA() -> TID = 0xe4 B::slotB() -> TID = 0x730 A::slotA() -> TID = 0xe4 B::slotB() -> TID = 0x730 A::slotA2() -> TID = 0xe4 B::slotB() -> TID = 0x730 A::slotA2() -> TID = 0xe4 A::slotA2() -> TID = 0xe4 A::slotA2() -> TID = 0xe4 A::slotA2() -> TID = 0xe4 ^C вроде все так как мне нужно - но я не уверен что это заработает, если в классе А написать так: Код: void slotA() { Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: Dendy от Января 30, 2009, 16:18 Всё правильно, должно работать.
Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: kuzulis от Февраля 02, 2009, 16:25 хм... сделал так:
Код: void slotA() { но почему-то память жутко утекает о_О . вроде ж в этом примере не создаются никакие объекты! Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: Dendy от Февраля 02, 2009, 16:37 В слоте остановлен цикл событий для потока А. События для него накапливаются, но никто их не обрабатывает.
Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: kuzulis от Февраля 02, 2009, 16:42 Цитировать В слоте остановлен цикл событий для потока А. События для него накапливаются, но никто их не обрабатывает. 1. хм... ткните пальцем :) я не понял... яж нигде не останавливал цикл событий!2. я ж слотом цепляюсь за сигнал.. т.е получается - обрабатываю! Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: Dendy от Февраля 02, 2009, 17:31 forever - это и есть остановка итерации. Причём без условия выхода из цикла, так вообще нельзя. Для этого потока всё остальное кроме этого цикла выполняться не будет.
Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: BRE от Февраля 02, 2009, 17:32 1. хм... ткните пальцем :) я не понял... яж нигде не останавливал цикл событий! Ты его не запускаешю.Для начала обработки событий, в run() нужно выполнить QThread::exec(). Код
Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: kuzulis от Февраля 02, 2009, 18:27 Цитировать Для начала обработки событий, в run() нужно выполнить QThread::exec(). ну у меня ж это есть!Код:
Цитировать forever - это и есть остановка итерации. Причём без условия выхода из цикла, так вообще нельзя. Для этого потока всё остальное кроме этого цикла выполняться не будет. это получается что если в A::slotA() будет вечный цикл, то до exec() очередь не дойдет?----- хм... если так, то получается вообще замкнутый круг.. :( , т.е нереально реализоватьвообще вот эту идею: 1. Имеется подсистема А в приложении (которая является отдельным потоком) и которая "вечно" в цикле анализирует некий массив данных.... суть анализа заключается в получении данных (опросе) из неких удаленных девайсов и сравнении полученных значений с предыдущим шагом... и если значение отличается - то выдать сигнал! (т.е выдать сигнал, если данные изменились) 2, Имеется подсистема В в приложении (которая тоже является потоком) и которая "отлавливает" сигнал, полученный от подсистемы А и выполняет свой алгоритм! Необходимо, чтобы : 1. главный поток приложения был - отдельно 2. поток подсистемы А выполнялся - отдельно (и все методы класса А выполнялись в этом потоке) 3. поток подсистемы В выполнялся - отдельно (и все методы класса В выполнялись в этом потоке) т.е как минимум иметь три "вечно" работающих потока! я что-то уже растерян, не представляю как это уже реализовать! Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: ритт от Февраля 02, 2009, 18:37 зачем вечный цикл выполняется в _слоте_ объекта А? если нужен вечный цикл и одновременно необходимы слоты в некотором потоке, используй таймер. если слоты не нужны, замени петлю событий (exec()) в этом потоке на цикл с условием выхода (при останове/разрушении потока и т.п.)
Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: BRE от Февраля 02, 2009, 19:11 я что-то уже растерян, не представляю как это уже реализовать! Вот смотри вариант с таймером: Код
Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: kuzulis от Февраля 02, 2009, 19:29 вот, переписал по-другому:
ab.h Код:
так правильно (корректно) ? Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это? Отправлено: kuzulis от Февраля 02, 2009, 19:36 2 Константин & 2 ВRE & 2 Dendy, спасибки за наводку ! :)
щас проверил в Linux с таймером в 10мс - вроде не кушает память.. завтра проверю в WinXP :) ЗЫ: за то что я не корректно в примерах высвобождаю указатели - просьба не бить жестко, т.к примерчики чисто теоретическо-практического-тестового плана! |