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

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

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Передать значение из главного потока в дочерний  (Прочитано 9837 раз)
RedDog
Гость
« : Октябрь 21, 2011, 14:15 »

Есть основной поток, в котором создаются дочерние, при создании нового дочернего потока, необходимо передать в уже работающие некоторое значение, через сигнал/слот почему то не работает:
Код:
class CMain
{
...
    void GenerateThreads();
signals:
    void setValue(int);
};

void CMain::GenerateThreads()
{
    for (int i = 0; i< 10; i++)
    {
        WorkThread *thread = new WorkThread();
        connect(this, SIGNAL(setValue(int)), thread, SLOT(on_setValue(int)));
        thread->start();
        emit setValue(i);
    }
}

class WorkThread: public QThread
{
...
    void run();
signals:
    void setValue(int)
slots:    
    void on_setValue(int)
};

void WorkThread::run()
{
    CWorker *worker = new CWorker();
    connect(this, SIGNAL(setValue(int)), worker, SLOT(on_setValue(int)));
    worker->doWork();
    exec();
}

void WorkThread::on_setValue(int _value)
{
    emit setValue(_value);    
}

class CWorker
{
...
    int a;
    void doWork();  
slots:    
    void on_setValue(int)
};

void CWorker::on_setValue(int _value)
{
    a = _value;
}

void CWorker::doWork()
{
    while (tue)
    {
        int b = a;
        msleep(b);
    }    
}

Как правильно оповестить дочерние потоки об изменении какого либо параметра? При том что они в цикле что то считают с перерывами на сон.
Записан
Странник
Гость
« Ответ #1 : Октябрь 21, 2011, 15:17 »

дочерние потоки крутятся у вас в doWork(), а цикл обработки событий тем временем не запущен. по-моему, лучше будет создать в потоке таймер, по сигналу которого будет вызываться слот doWork().
« Последнее редактирование: Октябрь 21, 2011, 15:19 от Странник » Записан
RedDog
Гость
« Ответ #2 : Октябрь 21, 2011, 21:01 »

doWork() это просто отдельная функция объекта, который работает в дочернем потоке.
Вообще тут смысл не в таймере, а в том, что есть условно бесконечный цикл в объекте дочернего потока, и необходимо управлять определенными данными внутри этого бесконечного цикла, причем управление должно осуществляться из главного потока.
Т.е. вопрос можно переформулировать так: как "заморозить" выполнение дочернего потока, изменить в нем данные, и запустить его на продолжение с новыми данными, при условии, что в дочернем потоке есть бесконечный цикл?
« Последнее редактирование: Октябрь 21, 2011, 21:03 от RedDog » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #3 : Октябрь 21, 2011, 21:27 »

дочерние потоки крутятся у вас в doWork(), а цикл обработки событий тем временем не запущен.
Логичное соображение, но дело довольно темное, каким-то образом Qt умеет хранить события до тех пор пока не запустится eventLoop.

Т.е. вопрос можно переформулировать так: как "заморозить" выполнение дочернего потока, изменить в нем данные, и запустить его на продолжение с новыми данными, при условии, что в дочернем потоке есть бесконечный цикл?
Непонятно какой цикл имеется ввиду - свой или exec() (который Вы тоже запускаете). Если свой, то все то что уже многократно обсуждалось для "как остановить": нитка проверяет флажок, если он взведен, то забирает новые данные и работает с ними. Понятно что проверку надо вставлять в код нитки (и возможно во многие места), а также что "сразу" нитка перестроиться не сможет. Но никаких волшебных/легких путей здесь нет.
Записан
Странник
Гость
« Ответ #4 : Октябрь 21, 2011, 23:28 »

doWork() это просто отдельная функция объекта, который работает в дочернем потоке.
Вообще тут смысл не в таймере, а в том, что есть условно бесконечный цикл в объекте дочернего потока, и необходимо управлять определенными данными внутри этого бесконечного цикла, причем управление должно осуществляться из главного потока.
Т.е. вопрос можно переформулировать так: как "заморозить" выполнение дочернего потока, изменить в нем данные, и запустить его на продолжение с новыми данными, при условии, что в дочернем потоке есть бесконечный цикл?
собственно я вам и предлагаю в качестве условно-бесконечного цикла использовать цикл обработки событий потока. для этого функцию doWork необходимо сделать слотом. это позволит выполнять doWork в потоке, не прерывая его работу при возврате из этого слота, а также запускать его в потоке уже после запуска цикла обработки событий. таким образом ваш поток сможет обрабатывать накопившиеся в очереди события (например, вызов слота on_setValue) после завершения doWork(), либо в процессе ее выполнения с помощью вызова processEvents().
Код:
class CMain
{
...
    void GenerateThreads();
signals:
    void setValue(int);
};

void CMain::GenerateThreads()
{
    for (int i = 0; i< 10; i++)
    {
        WorkThread *thread = new WorkThread();
        connect(this, SIGNAL(setValue(int)), thread, SLOT(on_setValue(int)));
        thread->start();
        QMetaObject::invokeMethod(thread, SLOT(doWork()), Qt::QueuedConnection);
        emit setValue(i);
    }
}

class WorkThread: public QThread
{
...
    int a;
signals:
    void setValue(int);
slots:    
    void doWork();
    void on_setValue(int);
};

void WorkThread::on_setValue(int _value)
{
    a = _value;
}

//вариант 1
void WorkThread::doWork()
{
        int b = a;
        ...
        QTimer::singleShot(b, this, SLOT(doWork()));
}    

//вариант 2
void WorkThread::doWork()
{
        while (true)
        {
            int b = a;
            ...
            msleep(b);
            qApp()->processEvents();
        }
}    

Логичное соображение, но дело довольно темное, каким-то образом Qt умеет хранить события до тех пор пока не запустится eventLoop.
хранить-то хранит, но не обрабатывает. разве что попробовать processEvents вызвать.
« Последнее редактирование: Октябрь 21, 2011, 23:31 от Странник » Записан
RedDog
Гость
« Ответ #5 : Октябрь 22, 2011, 09:28 »

Непонятно какой цикл имеется ввиду - свой или exec() (который Вы тоже запускаете). Если свой, то все то что уже многократно обсуждалось для "как остановить": нитка проверяет флажок, если он взведен, то забирает новые данные и работает с ними. Понятно что проверку надо вставлять в код нитки (и возможно во многие места), а также что "сразу" нитка перестроиться не сможет. Но никаких волшебных/легких путей здесь нет.
[/quote]Цикл имеется ввиду свой while(true) который запускается внутри exec().
Что бы остановить его надо ввести какое то значение, а оно не вводится, т.к.  цикл бесконечный и не отвечает на внешние запросы, т.е. до его окончания объект не может реагировать на сигналы извне.
prcessEvent внутри цикла был бы выходом, но он только для QCoreApplication, а как его реализовать для отдельного самописного класса хз.
Записан
BRE
Гость
« Ответ #6 : Октябрь 22, 2011, 09:33 »

А если цикла while(true) заменить на:
Код
C++ (Qt)
bool running = true;
...
while( running )
{
}
 
или
Код
C++ (Qt)
bool stopped = false;
...
while( true )
{
   if( stopped )
       break;
}
 

Подмигивающий

P.S. Кстати и цикла обработки событий внутри своих циклов легко крутить, если воспользоваться классом QEventLoop.
Записан
Странник
Гость
« Ответ #7 : Октябрь 22, 2011, 10:56 »

prcessEvent внутри цикла был бы выходом, но он только для QCoreApplication, а как его реализовать для отдельного самописного класса хз.
вызов QCoreApplication::processEvents() производит обработку очереди событий для вызывающего потока, что вас не устраивает?
« Последнее редактирование: Октябрь 22, 2011, 10:58 от Странник » Записан
RedDog
Гость
« Ответ #8 : Октябрь 22, 2011, 11:31 »

А если цикла while(true) заменить на:
Код
C++ (Qt)
bool stopped = false;
...
while( true )
{
   if( stopped )
       break;
}
 
Вот грубо говоря мне эту bool stopped и надо изменять, но оно не изменяется, т.к. не доходит сигнал, что надо ее изменить, т.к. крутится бесконечный цикл и обработка сообщений не происходит.
Записан
RedDog
Гость
« Ответ #9 : Октябрь 22, 2011, 11:33 »

prcessEvent внутри цикла был бы выходом, но он только для QCoreApplication, а как его реализовать для отдельного самописного класса хз.
вызов QCoreApplication::processEvents() производит обработку очереди событий для вызывающего потока, что вас не устраивает?
т.е. если вызвать:

Код:
while(true)
{
    QCoreApplication::processEvent();
   /// bla bla bla
}
с учетом того, что этот цикл в дочернем потоке, то поможет? (имеется ввиду поможет конкретному дочернему потоку)
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #10 : Октябрь 22, 2011, 12:02 »

Вот грубо говоря мне эту bool stopped и надо изменять, но оно не изменяется, т.к. не доходит сигнал, что надо ее изменить, т.к. крутится бесконечный цикл и обработка сообщений не происходит.
Главная нитка изменяет stopped, а дочерняя это может отловить - в любой цикл можно вставить if (stopped)
Записан
RedDog
Гость
« Ответ #11 : Октябрь 22, 2011, 15:32 »

Вот грубо говоря мне эту bool stopped и надо изменять, но оно не изменяется, т.к. не доходит сигнал, что надо ее изменить, т.к. крутится бесконечный цикл и обработка сообщений не происходит.
Главная нитка изменяет stopped, а дочерняя это может отловить - в любой цикл можно вставить if (stopped)
Если посмотреть код из первого поста, то я так и делаю, но через сигнал/слот это не проходит,т.е. цикл обработки сообщений зависает до окончания работы while(true).
Как заставить отработать цикл обработки  сообщений?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #12 : Октябрь 22, 2011, 16:01 »

Если посмотреть код из первого поста, то я так и делаю, но через сигнал/слот это не проходит,т.е. цикл обработки сообщений зависает до окончания работы while(true).
Как заставить отработать цикл обработки  сообщений?
То чего нет зависнуть не может, eventLoop создается в exec(). Если я правильно понял Вы хотите все делать на сигналах, без самопальных флажков. Тогда в дочерней нитке просто войдите в exec (не перекрывайте run). Нитка будет ждать сигнала/события. Пошлите его из главной, нитка начнет свое doWork, в котором уже можно звать processEvents и принимать следующие сигналы.
Записан
RedDog
Гость
« Ответ #13 : Октябрь 22, 2011, 18:42 »

Исходя из Ваших слов у меня вырисовывается картина кода, точно такая же как я привел в 1-м посте.
Но она, увы, не работает
Если не сложно, покажите псевдокодом.
Записан
Странник
Гость
« Ответ #14 : Октябрь 22, 2011, 19:25 »

Исходя из Ваших слов у меня вырисовывается картина кода, точно такая же как я привел в 1-м посте.
Но она, увы, не работает
Если не сложно, покажите псевдокодом.
такой вариант я приводил несколькими постами выше:
Код:
class CMain
{
...
    void GenerateThreads();
signals:
    void setValue(int);
};

void CMain::GenerateThreads()
{
    for (int i = 0; i< 10; i++)
    {
        WorkThread *thread = new WorkThread();
        connect(this, SIGNAL(setValue(int)), thread, SLOT(on_setValue(int)));
        thread->start();
        QMetaObject::invokeMethod(thread, SLOT(doWork()), Qt::QueuedConnection);
        emit setValue(i);
    }
}

class WorkThread: public QThread
{
...
    int a;
signals:
    void setValue(int);
slots:   
    void doWork();
    void on_setValue(int);
};

void WorkThread::on_setValue(int _value)
{
    a = _value;
}

//вариант 1
void WorkThread::doWork()
{
        int b = a;
        ...
        QTimer::singleShot(b, this, SLOT(doWork()));
}   

//вариант 2
void WorkThread::doWork()
{
        while (true)
        {
            int b = a;
            ...
            msleep(b);
            qApp()->processEvents();
        }
}   
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


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