Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум на CrossPlatform.RU _ Qt Общие вопросы _ QThread

Автор: gpepsi 4.10.2011, 20:37

как из потоковой функции можно понять, что ожидается завершение потока ?

Автор: ViGOur 5.10.2011, 10:00

Послать ей сигнал.
Или ввести какую-нибудь переменную, например bool m_bThreadStop = false;, которую периодически проверять.

Автор: gpepsi 5.10.2011, 12:34

Цитата(ViGOur @ 5.10.2011, 11:00) *
Или ввести какую-нибудь переменную, например bool m_bThreadStop = false;, которую периодически проверять.


у меня куча потоков. для каждой заводить переменную ?

Цитата(ViGOur @ 5.10.2011, 11:00) *
Послать ей сигнал.


а как внутри определить ?

ну если внутри
while(true)
{
}

никак не завершиться. нужно ожидать на чем-то. Странно что этого не предусмотрели...

Автор: silver47 5.10.2011, 13:53

Цитата(gpepsi @ 5.10.2011, 14:34) *
у меня куча потоков. для каждой заводить переменную ?


Если Вам необходимо тормозить все потоки одновременно, то проще завести одну переменную в главном потоке, а остальным передать указатель на нее.

Чем не подходит QThread::quit() ?

Автор: gpepsi 5.10.2011, 15:09

Цитата(silver47 @ 5.10.2011, 14:53) *
Чем не подходит QThread::quit() ?


а как это будет выглядеть ?

Автор: gpepsi 5.10.2011, 18:03

Цитата(silver47 @ 5.10.2011, 14:53) *
Чем не подходит QThread::quit() ?


а - понял, что имеется ввиду
 class MyThread : public QThread
{
public:
     void run();
};

void MyThread::run()
{
     QTcpSocket socket;
     // connect QTcpSocket's signals somewhere meaningful
     ...
     socket.connectToHost(hostName, portNumber);
     exec();
}


в главном потоке
main()
{
   QCoreApplication app(...);
   MyThread th;
   ...
   app.exec();
   ...
   th.quit();
   th.wait();
   return 0;

}


1. Это если все на сигналах построено, а если мне нужно крутить цикл, например, для чтения
while(...)
{
   ReadFile(...);
}


2. Что если слоты подключаются в главном потоке, а сигналы вызываются в дочернем ?

Автор: silver47 6.10.2011, 5:17

Имеется ввиду, что если у вас есть указатели на потоки, то можно вызвать метод QThread::quit(). А проверить есть ли запущенные потоки, кроме основного и подождать их завершения можно так:

if(QThreadPool::globalInstance()->activeThreadCount()) QThreadPool::globalInstance()->waitForDone();


Крутить цикл для чтения из чего? Из файла или Вы серверную\клиентскую сторону сетевого приложения пишете? Во втором случае, удобнее, как мне кажется, использовать сигнал readyRead().

Автор: ViGOur 6.10.2011, 9:01

Цитата(gpepsi @ 5.10.2011, 13:34) *
у меня куча потоков. для каждой заводить переменную ?

Зачем для каждого? Достаточно разок завести для базового, что-то вроде этого:

class MyThread : public QThread
{
     bool m_bExit;
public:
     void run();
};

void MyThread::run()
{
     // ...
     while( !m_bExit)
     {
        // ...
        ReadFile(...);
     }
}


Автор: gpepsi 6.10.2011, 13:35

Цитата(ViGOur @ 6.10.2011, 10:01) *
Зачем для каждого? Достаточно разок завести для базового, что-то вроде этого:


а как тогда с циклом обработки событий быть, если он запускается через exec, а мне нужно, чтоб поток посылал сигналы.

Автор: ViGOur 6.10.2011, 14:42

Или выносить в другой поток или не использовать цикл, а пользоваться только сигналами...

Автор: gpepsi 6.10.2011, 15:05

Цитата(ViGOur @ 6.10.2011, 15:42) *
Или выносить в другой поток или не использовать цикл, а пользоваться только сигналами...


ну а если мне нужно и цикл крутить и сигналить ?

Автор: ViGOur 6.10.2011, 15:38

А ты попробуй.
Механизм сигналов и слотов асинхронный, если ты не будешь тупо всисеть в sleep в потоке, который должен получить сигнал, то значит всё долно работать.

И еще, как ты думаешь в твоём коде:

main()
{
   QCoreApplication app(...);
   MyThread th;
   ...
   app.exec();
   ...
   th.quit();
   th.wait();
   return 0;

}
дойдет выполнение до th.quit(); ?
Мне кажется, что дальше app.exec(); не пройдет. :)

Автор: gpepsi 6.10.2011, 17:08

Цитата(ViGOur @ 6.10.2011, 16:38) *
А ты попробуй.


а что тут пробовать
#include <QThread>

class Thread : public QThread {
    Q_OBJECT
private:
    virtual void run(void);

public :
    explicit Thread(QObject* parent) : QThread(parent) {}
    virtual ~Thread() {}

signals:
    void send(void);
};

class Owner : public QObject {
    Q_OBJECT
private:
    Thread m_thread;

    virtual void timerEvent ( QTimerEvent * event );

public :
    explicit Owner(QObject* parent = nullptr);
    virtual ~Owner() {}
    
public slots:
    void recv(void);
};


код
#include "main.h"
#include <QtCore/QCoreApplication>
#include <QDebug>

void Thread::run( void )
{
    forever
    {
        emit send();
        QThread::msleep(1000);
    }
}

Owner::Owner( QObject* parent /*= nullptr*/ ) : QObject(parent), m_thread(this)
{
    connect(&m_thread, SIGNAL(send()), this, SLOT(recv()));
    m_thread.start();

    startTimer(5000);
}

void Owner::recv( void )
{
    qDebug() << "received signal";
}

void Owner::timerEvent( QTimerEvent * event )
{
    m_thread.quit();
    m_thread.wait();
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    Owner owner;
    return a.exec();
}


без цикла обработки quit не прокатывает

Автор: ViGOur 6.10.2011, 17:18

Посмотри на: http://www.doc.crossplatform.ru/qt/4.7.x/qcoreapplication.html#processEvents, он как раз делает то, что тебе нужно...

Автор: silver47 6.10.2011, 17:40

Цитата
void Thread::run( void )
{
    forever
    {
        emit send();
        QThread::msleep(1000);
    }
}


Зачем это? Что Вы делаете в цикле то?

Автор: gpepsi 6.10.2011, 18:45

Цитата(ViGOur @ 6.10.2011, 18:18) *
Посмотри на: QCoreApplication::processEvents, он как раз делает то, что тебе нужно...


бесконечный цикл он все-равно не сбросит, так что без флага не обойтись :(

Автор: silver47 6.10.2011, 19:12

Так всетаки зачем бесконечный цикл то? Мое мнение такое - если бесконечный цикл - то наследоваться от QThread нафиг не нужно - делаем обычный QtConcurrent

Автор: ViGOur 6.10.2011, 19:17

processEvents не сбрасывает ничего, а просто дает отработать сигналам для данного потока.
А если цикл не просто бесконечный, с условием, тогда всё в порядке.

Автор: gpepsi 7.10.2011, 7:52

Цитата(ViGOur @ 6.10.2011, 20:17) *
А если цикл не просто бесконечный, с условием, тогда всё в порядке.

то есть самому контролировать выход ?
Цитата(ViGOur @ 6.10.2011, 20:17) *
processEvents не сбрасывает ничего, а просто дает отработать сигналам для данного потока.

руками вместо exec ?

Цитата(silver47 @ 6.10.2011, 20:12) *
Так всетаки зачем бесконечный цикл то? Мое мнение такое - если бесконечный цикл - то наследоваться от QThread нафиг не нужно - делаем обычный QtConcurrent


а чем он лучше и как решит это мою проблему ?

P.S. и кстати как быть с сигналами. Если объект создан в главном потоке, то и сигналы в главном потоке будут обрабатываться, а если объект создан в run ?

Автор: ViGOur 7.10.2011, 8:34

Цитата
то есть самому контролировать выход ?
Да, именно так. у тебя же цикл не с вечным sleep'ом, вот и вызывай на каждой его итерации processEvents. А он в свою очередь будет обрабатывать сигналы и вызывать что нужно...

Цитата
руками вместо exec ?
Да. Выше уже описал...

Цитата
P.S. и кстати как быть с сигналами. Если объект создан в главном потоке, то и сигналы в главном потоке будут обрабатываться, а если объект создан в run ?
Запомни, в каком потоке создан объек, в том он и обрабатывается. Если тебя это не устраивает, то после создания объекта ты его можешь передать в другой поток с помощью: http://www.doc.crossplatform.ru/qt/4.7.x/qobject.html#moveToThread

Автор: gpepsi 7.10.2011, 9:00

ViGOur, а если я создаю поток только для вычитывания и разбора данных. Далее я хочу разобранные данные отдать в GUI для отрисовки.
Получается, что в run я должен это все делать, а отдавать данные через сигнал. Если объект создан в главном потоке, то и сигнал будет
обработан в главном потоке, что позволит отрисовать их в GUI.
Причем processEvents будет не нужен, т.к. QCoreApplication::exec обрабатывает свой цикл событий.
Причем в данно случае я могу объекту потоку послать сигнал, который будет обработан в главном потоке.

Я правильно размышляю ?

Единственное остался вопрос - зачем тогда вообще создавать объекты в run как в примере

 class MyThread : public QThread
{
public:
     void run();
};

void MyThread::run()
{
     QTcpSocket socket;
     // connect QTcpSocket's signals somewhere meaningful
     ...
     socket.connectToHost(hostName, portNumber);
     exec();
}

если для GUI их все-равно придется отдавать в главный поток, что за нас делает сигнал

Кстати, если я не использую потоки, а только сигналы, например, вычитывая данные из сокета вся обработка будет в главном потоке, то приведет
к подвисанию GUI если данных очень много

P.S. А чем тогда QtConcurrent полезен ?

Автор: ViGOur 7.10.2011, 9:10

Чтобы было меньше вопросов, предлагаю тебе почитать вот что:
1. http://www.doc.crossplatform.ru/qt/4.5.0/threads.html
2. http://www.doc.crossplatform.ru/qt/4.5.0/signalsandslots.html

Там не так много букв как кажется, и как показывает практика как хотелось бы, и это базовые знания, которые нужно знать каждому, кто работает с Qt и использует потоки. Ну а без сигналов тут разумеется никуда.

И если после прочтения у тебя возникнут вопросы, то задавай их, но я думаю они сами по себе отпадут. :)

QtConcurrent, там тоде описан...

Форум Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)