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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: Периодическая обработка данных из другого потока  (Прочитано 3970 раз)
CountZero
Гость
« : Март 16, 2017, 14:27 »

Добрый день.

Имеется следующая задача: из основного потока программы запускаются  два потока.
Первый поток в бесконечном цикле получает осуществляет запросы к внешнему устройству, получает от него данные, обрабатывает их и генерирует сигнал о том, что новые данные пришли. Второй поток должен получить данные из первого потока, выдать управляющий сигнал, и после этого выдача управляющих сигналов должна быть заблокирована на некоторое время, в зависимости от результатов обработки данных от первого потока. Собственно вопрос по реализации этой самой блокировки как ее сделать?

Для экспериментов накидал следующий код:

1. Поток имитирующий получение данных от устройства.
Код:
MainThread::MainThread()
{
    run=true;
    tmr = new QTime;
}

void MainThread::process()
{
    double PVSim;
    tmr->start();
    while (run)
    {
        PVSim = 2+sin(tmr->elapsed());
        emit SendData(PVSim);
        Sleep(100);
    }
    emit finished();
}

void MainThread::stop()
{
    run=false;
}

2. Поток имитирующий управляющий:

Код:
ControlThread::ControlThread()
{
}

void ControlThread::process()
{
    percent =  PV * 100 / 2;
    emit AutoFirst(percent,1,1);
}

void ControlThread::stop()
{
    emit finished();
}

void ControlThread::GetPV(double data)
{
    PV = data;
    process();
}

3. Создание потока, настройка сигналов, слотов в основном:
Код:
    threadControl = new QThread;
    threadMain = new QThread;

    Main = new MainThread;
    Control = new ControlThread(1,16,12);

    Main->moveToThread(threadMain);
    Control->moveToThread(threadControl);

    connect(threadControl, SIGNAL(started()), Control, SLOT(process()));
    connect(Control, SIGNAL(finished()), threadControl, SLOT(quit()));
    connect(Control, SIGNAL(finished()), Control, SLOT(deleteLater()));
    connect(threadControl, SIGNAL(finished()), threadControl, SLOT(deleteLater()));
    connect(this,SIGNAL(SetSP(double)),Control,SLOT(GetSP(double)));
    connect(Control,SIGNAL(AutoFirst(int,int,int)),this,SLOT(Auto(int,int,int)));

    connect(threadMain, SIGNAL(started()), Main, SLOT(process()));
    connect(Main, SIGNAL(finished()), threadMain, SLOT(quit()));
    connect(Main, SIGNAL(finished()), Main, SLOT(deleteLater()));
    connect(threadMain, SIGNAL(finished()), threadMain, SLOT(deleteLater()));
    connect(Main,SIGNAL(SendData(double)),Control,SLOT(GetPV(double)));


В такой реализации у нас "управляющий" поток выдает сигналы с частотой опроса устройства - данные пришли, сигнал выдали. А требуется чтобы он на основании данных выдал сигнал, потом X секунд подождал (данные при этом можно обновлять, реакция не требуется), а через Х секунд началась новая итерация. 
Пробовал вариант со Sleep, но он естественно просто замораживает отработку, а сигналы приходят и после "разморозки" начинается отработка каждого блока из пришедших данных, а нужно отработать только по последним данным.
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #1 : Март 17, 2017, 09:32 »

Не сильно разбирался в Вашем коде, но, кажется, вам должен подойти таймер, генерирующий сигналы на таймауте.
http://doc.qt.io/qt-5/qtimer.html#timeout
Возможно будет достаточным заменить бесконечный цикл на него.
Записан
CountZero
Гость
« Ответ #2 : Март 17, 2017, 10:04 »

Не сильно разбирался в Вашем коде, но, кажется, вам должен подойти таймер, генерирующий сигналы на таймауте.
http://doc.qt.io/qt-5/qtimer.html#timeout
Возможно будет достаточным заменить бесконечный цикл на него.

Проблем с бесконечным циклом как раз нет, и его менять не надо. Суть как раз в том, что данные приходят и должны приходить с частотой большей чем частота реакции на данные. Менять надо было поведение второго потока, в котором цикла нет. Про QTimer и его timeout() естественно знаю, вопрос был как корректно организовать взаимодействие.

Проблему уже решил самостоятельно. На самом деле все оказалось настолько очевидным, что даже странно, что сразу не пришло в голову. В следующем сообщении опишу решение.
Записан
CountZero
Гость
« Ответ #3 : Март 17, 2017, 10:47 »

Проблема решена.

Для того чтобы решить задачу требуется добавить таймер в MainWindow, который и будет периодически запускать отработку второго процесса.

В MainWindow:
1. Добавляем QTimer* tmr.
2. Добавляем в MainWindow слот SetTimer(int tm) в котором будем запускать таймер необходимой задержки командой tmr->start(tm);
3. Соединяем сигнал таймера tmr->timeout() со слотом process() второго процесса
4. Cоединяем сигнал delay(int tm) второго процесса со слотом SetTimer(int tm)

В ControlThread:
1. Добавляем сигнал delay(int tm),
2. Убираем запуск process() из getPV(double data)
3. Добавляем в конце выполнения всей логики process() выработку сигнала delay(miliseconds)

У нас получается этакое кольцо - таймер запускает process, process запускает таймер, для начального входа в этот цикл используется сигнал от нити started(), который запустит process() первый раз, чтобы все было нормально в конструкторе следует  проинициализировать данные таким образом чтобы первый прогон process() без полученных данных отработал корректно.

Код:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
    setupUi(this);

    threadControl = new QThread;
    threadMain = new QThread;

    Main = new MainThread;
    Control = new ControlThread(1,16,12);

    Main->moveToThread(threadMain);
    Control->moveToThread(threadControl);

    connect(threadControl, SIGNAL(started()), Control, SLOT(process()));
    connect(Control, SIGNAL(finished()), threadControl, SLOT(quit()));
    connect(Control, SIGNAL(finished()), Control, SLOT(deleteLater()));
    connect(threadControl, SIGNAL(finished()), threadControl, SLOT(deleteLater()));
    connect(this,SIGNAL(SetSP(double)),Control,SLOT(GetSP(double)));
    connect(Control,SIGNAL(AutoFirst(int,int,int)),this,SLOT(Auto(int,int,int)));

    connect(threadMain, SIGNAL(started()), Main, SLOT(process()));
    connect(Main, SIGNAL(finished()), threadMain, SLOT(quit()));
    connect(Main, SIGNAL(finished()), Main, SLOT(deleteLater()));
    connect(threadMain, SIGNAL(finished()), threadMain, SLOT(deleteLater()));
    connect(Main,SIGNAL(SendData(double,int)),Control,SLOT(GetPV(double,int)));
    
    threadControl->start();
    threadMain->start();
    tmr = new QTimer;

    connect(tmr,SIGNAL(timeout()),Control,SLOT(process()));
    connect(Control,SIGNAL(delay(int)),this,SLOT(setTimer(int)));
}

void MainWindow::setTimer(int tm)
{
    tmr->start(tm);
}


Код:
void ControlThread::process()
{
    percent =  SensPV * 100 / 2;
    emit delay(miliseconds);
}
void ControlThread::GetPV(double data)
{
    SensPV = data;
}
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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