Russian Qt Forum
Май 17, 2024, 23:20 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2 3   Вниз
  Печать  
Автор Тема: Потоки, сигналы, слоты и потенциальные касяки если связать все это?  (Прочитано 23147 раз)
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« : Январь 29, 2009, 13:22 »

Потоки, сигналы, слоты и потенциальные касяки связанные с этим?

Допустим ,например, в моем приложении имеется две "подсистемы" А и B.
Эти подсистемы представляют собой два экземпляра классов, наследуемых от QThread.
1. Поток А в бесконечном цикле передает потоку В сигнал sgReadData(int i)
о том что он хочет прочитать некие данные.
2.Поток В принял этот сигнал, выполнил свой слот и выдал потоку А сигнал о том,
  что данные готовы...
3. поток А принял от потока В сигнал о том что данные готовы и обновил у себя их

(про защиту данных QList от потокобезопасности я опускаю речь Улыбающийся., сейчас не это главное узнать! )

//---------- подсистема А

Код:
class A: public QThread
{
signals:
   void sgReadData(int i)
protected:
   void run();
private slots:
   void slUpdateData(int i, int data);

private:
   QList<int> list;
}
//
void A::run()
{
   while (1)
   {
     //перебираем все записи в QList и емиттим сигналы о том что классу А нужно получить новые данные
     for (int j=0;j<list.size();++j) {
        emit sgReadData(j);
     }
   }
}
//обновляем данные
void A::slUpdateData(int i, int data);
{
   list[i] = data;
}

//---------- подсистема B
Код:
class B: public QThread
{
signals:
   void sgDataReady(int i, int data);
protected:
   void run();
private slots:
   void slReadData(int i);

private:
   List<int> list;
}
//
void B::run()
{
 ///  НАДО ЛИ ЧТО ЗДЕСЬ ПИСАТЬ???
}
//
void B::slReadData(int i)
{
   emit sgDataReady(int i, list.at(i));
}

в приложении делаем так:

Код:
A *threadA = new(A);
B *threadB = new(B);

connect(A, SIGNAL(sgReadData(int)), B, SLOT(slReadData(int)));
connect(B, SIGNAL(sgDataReady(int,int)), A, SLOT(slUpdateData(int,int)));

threadA->start();
threadB->start();


Вопрос:
1. корректно ли так реализовывать мою идею? (т.е не "захлебнутся" ли потоки (приложение)  таким количеством данных)
2. Какие "косяки" могут вылезти?
3. что если в сигнале класса В sgDataReady, указать для данных не тип int а указатель на *int ? (хотя везде в
    ассистенте передают типы а не указатели!)



« Последнее редактирование: Январь 29, 2009, 13:27 от kuzulis » Записан

ArchLinux x86_64 / Win10 64 bit
Rcus
Гость
« Ответ #1 : Январь 29, 2009, 13:48 »

Assistant -> Thread Support in Qt же.
1. Работать не будет, читайте ман (нужна петля обработки событий)
2. не обрабатывается команда завершения потока, возможно нарушение приоритетов (starvation)
3. А зачем?
Записан
ритт
Гость
« Ответ #2 : Январь 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
Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #3 : Январь 29, 2009, 14:01 »

2 kuzulis: Возми книгу Jasmin Blanchette, Mark Summerfield C++ GUI Programming with Qt 4 (существут перевод этой книги на русский) и прочти 14 раздел Multithreading.
Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #4 : Январь 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 в свое внутреннее некое хранилище данных , у которого свои идентификаторы

т.е листы - это просто типа массивов каких-то данных (в принципе я массивы мог бы всунуть)

вот как мне нужно сделать!!!
типа приложение состоять должно из нескольких подсистем А, В, С .. и т.п ..  которые должны работать в своих потоках и общаться между собой (передавать/принимать данные)  желательно только с помошью сигналов и слотов, раз уж придумали тролли этот механизм!

фухх.. Улыбающийся


« Последнее редактирование: Январь 29, 2009, 14:38 от kuzulis » Записан

ArchLinux x86_64 / Win10 64 bit
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #5 : Январь 29, 2009, 14:24 »

Цитировать
2 kuzulis: Возми книгу Jasmin Blanchette, Mark Summerfield C++ GUI Programming with Qt 4 (существут перевод этой книги на русский) и прочти 14 раздел Multithreading.
там нет того что мне нужно! там все не то!
Записан

ArchLinux x86_64 / Win10 64 bit
ритт
Гость
« Ответ #6 : Январь 29, 2009, 14:38 »

Цитировать
Цитировать
1. Работать не будет, читайте ман (нужна петля обработки событий)
блина... читаю... ток голова пухнет! и что - то не могу понять!
от чего там пухнуть? хочешь, чтобы в потоке вызывался сигнал - используй ивентлуп (exec() потоку либо собственный). а вечный цикл убрать. /* кстати, "while (1)" называется "forever" Улыбающийся */
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #7 : Январь 29, 2009, 14:43 »

Цитировать
от чего там пухнуть? хочешь, чтобы в потоке вызывался сигнал - используй ивентлуп (exec() потоку либо собственный). а вечный цикл убрать. /* кстати, "while (1)" называется "forever" Улыбающийся */
Я не понял насчет евентлупа! Я запуталсо! Грустный
Записан

ArchLinux x86_64 / Win10 64 bit
ритт
Гость
« Ответ #8 : Январь 29, 2009, 15:48 »

тогда задай себе вопрос: "а нужны ли вообще мне эти потоки?" Улыбающийся
если ответ себе будет "да, нужны - без них никак", брось всё на время - отдохни, а затем начинай читать про потоки с самого начала...
без понимания примитивов работы с потоками, того и гляди, получится приложение, "защищённое от потокобезопасности" Улыбающийся
в качестве альтернативы посмотри на QtConcurrent
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #9 : Январь 29, 2009, 16:10 »

да! нужны! Улыбающийся

я с exec() не очень понял, т.к примеров нету!

т.е если я в вместо A->start() напишу А->exec() - то запустится цикл обработки сообщений и следовательно можно не переопределять ф-ю run() ?
« Последнее редактирование: Январь 29, 2009, 16:20 от kuzulis » Записан

ArchLinux x86_64 / Win10 64 bit
ритт
Гость
« Ответ #10 : Январь 29, 2009, 16:51 »

а ничего, что QThread::exec() защищённый (protected)?
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #11 : Январь 29, 2009, 16:55 »

О_о.. башка не варит под конец дня...

Значит надо делать так?
Код:
void B::run
{ exec(); }

а в main.c писать: B->start() ?
так что-ли ? Улыбающийся
Записан

ArchLinux x86_64 / Win10 64 bit
Dendy
Гость
« Ответ #12 : Январь 29, 2009, 16:59 »

Именно. А завершить выолнение exec() с помощью вызова thread->quit() или thread->exit( myReturnCode ).
Записан
ритт
Гость
« Ответ #13 : Январь 29, 2009, 17:18 »

Именно. А завершить выолнение exec() с помощью вызова thread->quit() или thread->exit( myReturnCode ).

а ещё можно сделать так:
Код
C
B::~B()
{
 quit();
 wait();
}
 
и безопасно удалять через delete thread; Улыбающийся

либо
Код
B::B(...)
{
 connect(this, SIGNAL(finished()), this, SLOT(deleteLater()));
}
 
и удалять через thread->stop(); Улыбающийся
« Последнее редактирование: Январь 29, 2009, 17:28 от Константин » Записан
Dendy
Гость
« Ответ #14 : Январь 29, 2009, 17:29 »

2 Константин, вот шустрый, я уже почти написал как нужно правильно.
Записан
Страниц: [1] 2 3   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.107 секунд. Запросов: 20.