Russian Qt Forum

Qt => Общие вопросы => Тема начата: kuzulis от Января 29, 2009, 13:22



Название: Потоки, сигналы, слоты и потенциальные касяки если связать все это?
Отправлено: kuzulis от Января 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 ? (хотя везде в
    ассистенте передают типы а не указатели!)





Название: 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. Работать не будет, читайте ман (нужна петля обработки событий)
блина... читаю... ток голова пухнет! и что - то не могу понять!
от чего там пухнуть? хочешь, чтобы в потоке вызывался сигнал - используй ивентлуп (exec() потоку либо собственный). а вечный цикл убрать. /* кстати, "while (1)" называется "forever" :) */


Название: 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
{ exec(); }

а в 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 ).

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

либо
Код
B::B(...)
{
 connect(this, SIGNAL(finished()), this, SLOT(deleteLater()));
}
 
и удалять через 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
{
signals:
   void signal1()
public:
   Z();
   ~Z();
   void slotFunc1();
protected:
   void run();
}

Z::Z()
{
}

Z::~Z()
{
}

void Z::run()
{
   exec();// !!!
   //тут какие нить действия (и даже может быть в "бесконечном" цикле)
   ... действие 1
   ... действие 2
   ... действие N
}

void Z::slotFunc1()
{
   //тут какие нить действия
   ... действие 1
   ... действие 2
   ... действие N
   //тут емиттим сигнал
   emit signal1();
}

теперь напишу то что я думаю как оно работает (на сей момент) + какие у меня непонятки  :) Поправьте меня где неправ я! И напишите как работает!

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
Кстати, такой код выполнится в главном потоке, а не в порождённом:

Код
C++ (Qt)
Z * z = new Z;
connect( this, SIGNAL(mySignal()), z, SLOT(slotFunc()) );
z->start();
...
emit mySignal();
 

В этом случае слот отработает прямо внутри emit mySignal(), а ну внутри Z::run(), так как экземпляр потока находится в том же потоке, в котором был выполнен connect(). Чтобы вызвать слот внутри Z::run() нужно коннектить так:

Код
C++ (Qt)
connect( this, SIGNAL(mySignal()), z, SLOT(slotFunc()), Qt::QueuedConnection );
 


Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это?
Отправлено: ритт от Января 29, 2009, 20:42
точно? я не проверял код выше, но, помнится, по умолчанию для разных потоков используется Qt::QueuedConnection...и в таком случае слот как бы должен отрабатывать в своей петле...


Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это?
Отправлено: kuzulis от Января 29, 2009, 20:43
Цитировать
7. у тебя slotFunc1 НЕ слот. если вызвать slotFunc1 как функцию, она будет отрабатывать в вызывающем потоке. если вызвать slotFunc1 через событие, слот отработает в своём потоке (вызывающая точка находится в петле)

это слот, просто я забыл написать:
Код:
public slots:
   void slotFunc1();

Цитировать
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[])
{
    QApplication app(argc, argv);
    //printf("curr TID = %d\n",currentThreadId());
    return app.exec();
}


Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это?
Отправлено: kuzulis от Января 30, 2009, 10:28
написал код вот так:
Код:
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    printf("curr TID = %d\n",(int)QThread::currentThreadId());
    return app.exec();
}

он мне показывает то что надо или нет ? о_О


Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это?
Отправлено: ритт от Января 30, 2009, 11:49
Код
C
int main(int argc, char *argv[])
{
   QApplication app(argc, argv);
 
   qWarning() << "curr TP:" << QThread::currentThread();
   qWarning() << "curr TID:" << QThread::currentThreadId();
 
   return app.exec();
}
 
покажет указатель и натив-ид главного треда. вот и сравнивай эти циферки в такими же циферками других тредофф.


Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это?
Отправлено: kuzulis от Января 30, 2009, 12:49
в общем сделал я так:

классы:

Код:
class A : public QThread
{
    Q_OBJECT
signals:
    void sgFromA();
public slots:
    void slotA() {}
protected:
    void run() {
        sleep(2);
        qWarning() << "A::run() -> TID = " << QThread::currentThreadId();
        emit sgFromA();
        exec();
    }
};

class B: public QThread
{
    Q_OBJECT
/*
signals:
    void sgFromB();
*/
public slots:
    void slotB() {
        qWarning() << "B::slotB() -> TID = " << QThread::currentThreadId();
    }
protected:
    void run() {
        qWarning() << "B::run() -> TID = " << QThread::currentThreadId();
        exec();
    }
};

main

Код:
int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
    //qWarning() << "App TP:" << QThread::currentThread();
    qWarning() << "Application -> TID = " << QThread::currentThreadId();
    QThread *tA = new A;
    QThread *tB = new B;
    app.connect(tA, SIGNAL(sgFromA()), tB, SLOT(slotB()), Qt::QueuedConnection);
    tA->start();
    tB->start();
    return app.exec();
}

консоль мне выдала следующее:
Цитировать
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
{
    Q_OBJECT
signals:
    void sgFromA();
public slots:
    void slotA() {
        qWarning() << "A::slotA() -> TID = " << QThread::currentThreadId();
        emit sgFromA();
    }
private:

};

class B: public QObject
{
    Q_OBJECT
public slots:
    void slotB() {
        qWarning() << "B::slotB() -> TID = " << QThread::currentThreadId();
    }
private:
};

class ThA : public QThread
{
public:
    A *cA;
    ThA() { }
protected:
    void run() {
        qWarning() << "running ThA::run() -> TID = " << QThread::currentThreadId();
        cA = new A;
        forever {
            sleep(1);
            cA->slotA();
        }
    }
};

class ThB : public QThread
{
public:
    B *cB;
    ThB() { }
protected:
    void run() {
        qWarning() << "running ThB::run() -> TID = " << QThread::currentThreadId();
        cB = new B;
        exec();
    }
};

main

Код:
int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
    //qWarning() << "App TP:" << QThread::currentThread();
    qWarning() << "Application -> TID = " << QThread::currentThreadId();
    ThA *tA = new ThA;
    ThB *tB = new ThB;
    app.connect(tA->cA, SIGNAL(sgFromA()), tB->cB, SLOT(slotB()), Qt::QueuedConnection);
    tA->start();
    tB->start();
    return app.exec();
}

то консоль выводит :
Цитировать
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

Код:

#ifndef AB_H
#define AB_H
#include <QThread>
#include <QDebug>

class A : public QObject
{
    Q_OBJECT
signals:
    void sgFromA();
public slots:
    void slotA() {
        for (int i=0;i<5;++i) {
            qWarning() << "A::slotA() -> TID = " << QThread::currentThreadId();
            emit sgFromA();
        }
        //forever {
        //    qWarning() << "A::slotA() -> TID = " << QThread::currentThreadId();
        //    emit sgFromA();
        //}
    }
    void slotA2() {
        qWarning() << "A::slotA2() -> TID = " << QThread::currentThreadId();
    }
};

class B: public QObject
{
    Q_OBJECT
signals:
    void sgFromB();
public slots:
    void slotB() {
        qWarning() << "B::slotB() -> TID = " << QThread::currentThreadId();
        emit sgFromB();
    }
};

class ThA : public QThread
{
public:
    A *cA;
    ThA() { cA = new A; }
protected:
    void run() {
        qWarning() << "running ThA::run() -> TID = " << QThread::currentThreadId();
        cA->slotA();
        exec();
    }
};

class ThB : public QThread
{
public:
    B *cB;
    ThB() { cB = new B; }
protected:
    void run() {
        qWarning() << "running ThB::run() -> TID = " << QThread::currentThreadId();
        exec();
    }
};

#endif // AB_H

main.cpp

Код:
#include <QtCore>
#include <QCoreApplication>
#include <QDebug>


#include "ab.h"


int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
    //qWarning() << "App TP:" << QThread::currentThread();
    qWarning() << "Application -> TID = " << QThread::currentThreadId();
    ThA *tA = new ThA;
    ThB *tB = new ThB;
    tB->cB->moveToThread(tB);
    tA->cA->moveToThread(tA);
    QObject::connect(tA->cA, SIGNAL(sgFromA()), tB->cB, SLOT(slotB()), Qt::QueuedConnection);
    QObject::connect(tB->cB, SIGNAL(sgFromB()), tA->cA, SLOT(slotA2()), Qt::QueuedConnection);
    tA->start();
    tB->start();
    return app.exec();
}

вывод:
Цитировать
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() {
        //for (int i=0;i<5;++i) {
        //    qWarning() << "A::slotA() -> TID = " << QThread::currentThreadId();
        //    emit sgFromA();
        //}
        forever {
            qWarning() << "A::slotA() -> TID = " << QThread::currentThreadId();
            emit sgFromA();
        }
    }


Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это?
Отправлено: Dendy от Января 30, 2009, 16:18
Всё правильно, должно работать.


Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это?
Отправлено: kuzulis от Февраля 02, 2009, 16:25
хм... сделал так:
Код:
    void slotA() {
        //for (int i=0;i<5;++i) {
        //    qWarning() << "A::slotA() -> TID = " << QThread::currentThreadId();
        //    emit sgFromA();
        //}
        forever {
            qWarning() << "A::slotA() -> TID = " << QThread::currentThreadId();
            emit sgFromA();
        }
    }

но почему-то память жутко утекает о_О . вроде ж в этом примере не создаются никакие объекты!


Название: 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().

Код
C++ (Qt)
void MyThread::run()
{
// Создали нужные объекты.
// Приконектились куда надо.
// ...
exec(); // Запустили цикл обработки событий
}
 


Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это?
Отправлено: kuzulis от Февраля 02, 2009, 18:27
Цитировать
Для начала обработки событий, в run() нужно выполнить QThread::exec().
ну у меня ж это есть!
Код:
 
void run() {
        qWarning() << "running ThA::run() -> TID = " << QThread::currentThreadId();
        cA->slotA();
        exec();
    }

Цитировать
forever - это и есть остановка итерации. Причём без условия выхода из цикла, так вообще нельзя. Для этого потока всё остальное кроме этого цикла выполняться не будет.
это  получается что если в A::slotA() будет вечный цикл, то до exec() очередь не дойдет?

-----

хм... если так, то получается вообще замкнутый круг.. :( , т.е нереально реализоватьвообще вот эту идею:
1. Имеется подсистема А в приложении (которая является отдельным потоком) и которая "вечно" в цикле  анализирует некий массив данных....
суть анализа заключается в получении данных (опросе) из неких удаленных девайсов и сравнении полученных значений с предыдущим шагом... и если значение отличается - то выдать сигнал! (т.е выдать сигнал, если данные изменились)
2, Имеется подсистема В в приложении (которая тоже является потоком) и которая "отлавливает" сигнал, полученный от подсистемы А и выполняет свой алгоритм!

Необходимо, чтобы :
1. главный поток приложения был  - отдельно
2. поток подсистемы А выполнялся - отдельно (и все методы класса А выполнялись в этом потоке)
3. поток подсистемы В выполнялся - отдельно (и все методы класса В выполнялись в этом потоке)
т.е как минимум иметь три "вечно" работающих потока!

я что-то уже растерян, не представляю как это уже реализовать!


Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это?
Отправлено: ритт от Февраля 02, 2009, 18:37
зачем вечный цикл выполняется в _слоте_ объекта А? если нужен вечный цикл и одновременно необходимы слоты в некотором потоке, используй таймер. если слоты не нужны, замени петлю событий (exec()) в этом потоке на цикл с условием выхода (при останове/разрушении потока и т.п.)


Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это?
Отправлено: BRE от Февраля 02, 2009, 19:11
я что-то уже растерян, не представляю как это уже реализовать!

Вот смотри вариант с таймером:
Код
C++ (Qt)
void ThreadA::run()
{
QTimer timer;
connect( &timer, SIGNAL( timeout() ), SLOT( checkData() ) );
// Раз в секунду запускаем проверку данных
timer.start( 1000 );
 
exec();
}
 
void ThreadA::checkData()
{
// Проверили и при необходимости
emit dataCahnged(); // отправляем сигнал
}
 
 
void ThreadB::run()
{
connect( threadA, SIGNAL( dataChanged() ), SLOT( processData() ) );
 
exec();
}
 
void ThreadB::processData()
{
// Получили сигнал от А
// Забрали данные
// Обработали их
}
 



Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это?
Отправлено: kuzulis от Февраля 02, 2009, 19:29
вот, переписал по-другому:

ab.h
Код:

#ifndef AB_H
#define AB_H
#include <QThread>
#include <QDebug>
#include <QTimer>

class A : public QObject
{
    Q_OBJECT
signals:
    void sgFromA();
public slots:
    void slotA() {//слот где инициализируем таймер
        qWarning() << "A::slotA() -> TID = " << QThread::currentThreadId();
        QTimer *timer = new QTimer(this);
        connect(timer, SIGNAL(timeout()), this, SLOT(slotA1()));
        timer->start(10);
    }
    void slotA1() {//слот где по таймеру выполняем емиттинг сигнала
            qWarning() << "A::slotA1() -> TID = " << QThread::currentThreadId();
            emit sgFromA();
    }
    void slotA2() {//слот который выполняется при выдаче классом В сигнала
        qWarning() << "A::slotA2() -> TID = " << QThread::currentThreadId();
    }
};

class B: public QObject
{
    Q_OBJECT
signals:
    void sgFromB();
public slots:
    void slotB() {//слот, который выполняется при выдаче классом А сигнала
        qWarning() << "B::slotB() -> TID = " << QThread::currentThreadId();
        emit sgFromB();
    }
};

class ThA : public QThread
{
public:
    A *cA;
    ThA() { cA = new A; }
protected:
    void run() {
        qWarning() << "running ThA::run() -> TID = " << QThread::currentThreadId();
        cA->slotA();
        exec();
    }
};

class ThB : public QThread
{
public:
    B *cB;
    ThB() { cB = new B; }
protected:
    void run() {
        qWarning() << "running ThB::run() -> TID = " << QThread::currentThreadId();
        exec();
    }
};
#endif // AB_H

так правильно (корректно) ?



Название: Re: Потоки, сигналы, слоты и потенциальные касяки если связать все это?
Отправлено: kuzulis от Февраля 02, 2009, 19:36
2 Константин & 2 ВRE & 2 Dendy, спасибки за наводку ! :)

щас проверил в Linux с таймером в 10мс - вроде не кушает память.. завтра проверю в WinXP :)

ЗЫ: за то что я не корректно в примерах высвобождаю указатели - просьба не бить жестко, т.к примерчики чисто теоретическо-практического-тестового плана!