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

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

Страниц: 1 [2] 3   Вниз
  Печать  
Автор Тема: Потоки, сигналы, слоты и потенциальные касяки если связать все это?  (Прочитано 23075 раз)
ритт
Гость
« Ответ #15 : Январь 29, 2009, 17:44 »

дык, напиши Улыбающийся
лишним не будет...а там, глядишь, и на статью для вики наберётся...
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #16 : Январь 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() и т.п ? Так?

---------
вроде пока все непонятки что хочу узнать
Записан

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

1. да
2. да
3., 4. сигнализирование от петли событий не зависит - сигнализировать можно и без неё
5. код после exec() отработает только после останова потока
6. да
7. у тебя slotFunc1 НЕ слот. если вызвать slotFunc1 как функцию, она будет отрабатывать в вызывающем потоке. если вызвать slotFunc1 через событие, слот отработает в своём потоке (вызывающая точка находится в петле)
8. статус потока не зависит от вызовов слотов и т.п.
9. нет
10. до выхода из run()
11. да
Записан
Dendy
Гость
« Ответ #18 : Январь 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 );
 
Записан
ритт
Гость
« Ответ #19 : Январь 29, 2009, 20:42 »

точно? я не проверял код выше, но, помнится, по умолчанию для разных потоков используется Qt::QueuedConnection...и в таком случае слот как бы должен отрабатывать в своей петле...
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #20 : Январь 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 ! Грустный
Записан

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

точно? я не проверял код выше, но, помнится, по умолчанию для разных потоков используется Qt::QueuedConnection...и в таком случае слот как бы должен отрабатывать в своей петле...

У вас хорошая память, всё так и есть - для разных потоков. Только экземпляр Z находится в том же потоке, что и эмиттер сигнала. Присмотритесь. Это типичная ошибка как новичков, так и более продвинутых программистов.
Записан
ритт
Гость
« Ответ #22 : Январь 29, 2009, 21:11 »

> хм... а зачем тогда вообще вызывать exec() ?
выше уже объясняли...раза два! у тебя слот в этом потоке. и тебе ведь нужно чтобы он работал.
-----
не оставляй run() пустым. добавь в него exec().
Записан
Dendy
Гость
« Ответ #23 : Январь 29, 2009, 21:12 »

хм... а зачем тогда вообще вызывать exec() ?

Чтобы сработал ваш слот внутри exec(). Чтобы обьекты (QObject), созданные внутри run() получали события.

если я оставлю ф-ю run() пустой, то получается что после вызова Z->start() поток сразу завершится ... и удалится

Да. Другой вопрос с чего столько эмоций?
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #24 : Январь 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 ?
 


ЗЫ: т.к все-равно у меня в голове еще все смутно и концы с концами не сходятся!
« Последнее редактирование: Январь 30, 2009, 08:45 от kuzulis » Записан

ArchLinux x86_64 / Win10 64 bit
ритт
Гость
« Ответ #25 : Январь 30, 2009, 09:36 »

дебаж указатель на тред - тебе-то какая разница? что так циферя будет, что так...
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #26 : Январь 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();
}
« Последнее редактирование: Январь 30, 2009, 10:13 от kuzulis » Записан

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

Сообщений: 2812


Просмотр профиля
« Ответ #27 : Январь 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();
}

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

ArchLinux x86_64 / Win10 64 bit
ритт
Гость
« Ответ #28 : Январь 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();
}
 
покажет указатель и натив-ид главного треда. вот и сравнивай эти циферки в такими же циферками других тредофф.
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #29 : Январь 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 !
как это можно сделать?
Записан

ArchLinux x86_64 / Win10 64 bit
Страниц: 1 [2] 3   Вверх
  Печать  
 
Перейти в:  


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