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

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

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Таймер в потоке  (Прочитано 11607 раз)
deMax
Хакер
*****
Offline Offline

Сообщений: 600



Просмотр профиля
« : Сентябрь 05, 2018, 09:51 »

Нужен класс, который по таймеру из другого потока отправляет данные
Интерфейс :
Код:
QPointer<Checker> checker;
connect(checker, &Checker::newData, this, &MyClass::process, Qt::BlockingQueuedConnection); // process(QMap<QString, int>), QueuedConnection - не соединяется

Накидал реализацию:
.h
Код:
class Checker: public QObject
{
    Q_OBJECT
    QThread m_thread;
    QTimer m_timer;

signals:
    void stop();

private slots:
    void started();
    void stoped();
    void timeout();

public:
    Checker();
    ~Checker();
    Q_SIGNAL void newData(QMap<QString, int>);
};

.cpp
Код:
void Checker::started()
{
    m_timer.start(1000);
}

void Checker::stoped()
{
    m_timer.stop();
}

void Checker::timeout()
{
    emit newData({});
}

Checker::Checker()
{
    this->moveToThread(&m_thread);

    m_timer.moveToThread(&m_thread);
    m_thread.start();

    connect(&m_thread, &QThread::started, this, &Checker::started);
    connect(this, &Checker::stop, this, &Checker::stoped);
    connect(&m_timer, &QTimer::timeout, this, &Checker::timeout);
}

Checker::~Checker()
{
    emit stop();
    m_thread.quit();
    m_thread.wait();
}

Вроде работает, но валидно ли? И почему QueuedConnection не соединяет? Или через потоки только POD данные пробрасывать можно?
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3257


Просмотр профиля
« Ответ #1 : Сентябрь 05, 2018, 10:42 »

Очень криво. НЕ НАДО обертку над тредом прокидывать в тред.
Записан
deMax
Хакер
*****
Offline Offline

Сообщений: 600



Просмотр профиля
« Ответ #2 : Сентябрь 05, 2018, 12:57 »

Ок. А как правильно? только QTimer в другой поток выносить? И слот timeevent должен в потоке выполняться.
Еще проблема, не могу в проекте передать QMap<QString, MyStruct> с опцией QueuedConnection. Пишет: QObject::connect: Cannot queue arguments of type 'QMap<QString, MyStruct>'
Делал qRegistredMetaType, Q_DECLARE_METATYPE, все таже ошибка. Или отправлять пустой сигнал?
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3257


Просмотр профиля
« Ответ #3 : Сентябрь 05, 2018, 13:37 »

Ок. А как правильно? только QTimer в другой поток выносить? И слот timeevent должен в потоке выполняться.
Еще проблема, не могу в проекте передать QMap<QString, MyStruct> с опцией QueuedConnection. Пишет: QObject::connect: Cannot queue arguments of type 'QMap<QString, MyStruct>'
Делал qRegistredMetaType, Q_DECLARE_METATYPE, все таже ошибка. Или отправлять пустой сигнал?

Да, только таймер.

Тред1: Checker checker; QThread m_thread;
Тред2: QTimer m_timer.

Зачем timeout в потоке? Я бы предложил тогда сделать класс Worker и перегрузить у него timerEvent() вместо QTimer. Ну или добавить 4й объект, который будет делать работу по таймеру, но это больше boilerplate кода.

Чтобы передавалась мапа, надо зарегать тип, да; с этим может быть гемор, гугли. Возможно, MyStruct тоже надо зарегать. Ведь создается копия, значит Qt должна понимать, как скопировать тип.
Можно попробовать в QVariant завернуть, как воркэраунд.
Записан
deMax
Хакер
*****
Offline Offline

Сообщений: 600



Просмотр профиля
« Ответ #4 : Сентябрь 05, 2018, 14:36 »

Зачем timeout в потоке? Я бы предложил тогда сделать класс Worker и перегрузить у него timerEvent() вместо QTimer. Ну или добавить 4й объект, который будет делать работу по таймеру, но это больше boilerplate кода.
В Timeout у меня "тяжелый" код, тот который должен считаться в отдельном потоке. (Ну т.е. он легкий, но в гуйне ему делать нечего)

В принципе меня и вариант QtConcurrent::run устоил бы с while(!qApp->closingDown()) { ...hard...; sleep(10) }. Только программа при закрытие ждет 10 секундный интервал, чтоб поток завершить...
Записан
qate
Супер
******
Offline Offline

Сообщений: 1175


Просмотр профиля
« Ответ #5 : Сентябрь 05, 2018, 15:50 »

В Timeout у меня "тяжелый" код, тот который должен считаться в отдельном потоке.

а почему просто не выкинуть рассчитанные данные их класса другого потока в класс gui без таймера ?
Записан
deMax
Хакер
*****
Offline Offline

Сообщений: 600



Просмотр профиля
« Ответ #6 : Сентябрь 05, 2018, 20:29 »

а почему просто не выкинуть рассчитанные данные их класса другого потока в класс gui без таймера ?
У меня мониторинг постоянный, таймер нужен, но его можно и в гуйне запустить.

хорошо, есть некая функция
Код:
std::function<QList<Data>> someFunc = [](){return QStrorageInfo()....;};
и класс
Код:
class MyGuiClass: public QObject { public slot: void someMethod(QList<Data>); }

Нужно в потоке запустить someFuncton чтобы каждые N секунд гуйня получала список файлов. мониторинг задача фоновая, как правило на отлов ошибок и не очень важная и не должна отвлекать гуйню.

Задача пустяковая и решить её можно множеством способов, как не отстрелить себе ногу, а наиболее грамотно это сделать? Ну и чтоб ошибок потенциальных, возможных крешей и падений не было.
« Последнее редактирование: Сентябрь 05, 2018, 20:31 от deMax » Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4349



Просмотр профиля
« Ответ #7 : Сентябрь 05, 2018, 21:07 »

Самое простое это прямо в GUI-потоке запустить таймер, из обработчика которого запускать нужную функцию через QtConcurrent::run и отслеживать ее завершение с помощью QFutureWatcher. А после завершение обновлять результат.
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3257


Просмотр профиля
« Ответ #8 : Сентябрь 05, 2018, 22:11 »

+1 за конкурент
Записан
deMax
Хакер
*****
Offline Offline

Сообщений: 600



Просмотр профиля
« Ответ #9 : Сентябрь 05, 2018, 22:18 »

А создание/удаление потока? не будет ли проще поток постоянно держать открытым? Все таки не на go пишем, создание потока процедура не самая быстрая(конечно побыстрее чем лазить на диск, но все же). Или я не прав?
« Последнее редактирование: Сентябрь 05, 2018, 22:30 от deMax » Записан
sergek
Гипер активный житель
*****
Offline Offline

Сообщений: 862


Мы должны приносить пользу людям.


Просмотр профиля
« Ответ #10 : Сентябрь 05, 2018, 22:30 »

А создание/удаление потока? не будет ли проще поток постоянно держать открытым?
Runs function in a separate thread. The thread is taken from the global QThreadPool.
Записан

Qt 5.13.0 Qt Creator 5.0.1
Win10, Ubuntu 20.04
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #11 : Сентябрь 07, 2018, 06:32 »

а почему просто не выкинуть рассчитанные данные их класса другого потока в класс gui без таймера ?
У меня мониторинг постоянный, таймер нужен, но его можно и в гуйне запустить.

хорошо, есть некая функция
Код:
std::function<QList<Data>> someFunc = [](){return QStrorageInfo()....;};
и класс
Код:
class MyGuiClass: public QObject { public slot: void someMethod(QList<Data>); }

Нужно в потоке запустить someFuncton чтобы каждые N секунд гуйня получала список файлов. мониторинг задача фоновая, как правило на отлов ошибок и не очень важная и не должна отвлекать гуйню.

Задача пустяковая и решить её можно множеством способов, как не отстрелить себе ногу, а наиболее грамотно это сделать? Ну и чтоб ошибок потенциальных, возможных крешей и падений не было.
А зачем эту мапу вообще передавать/копировать? Сделать ее членом того же Checker'а, только защитить напр мутексом
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3257


Просмотр профиля
« Ответ #12 : Сентябрь 07, 2018, 22:40 »

А зачем эту мапу вообще передавать/копировать? Сделать ее членом того же Checker'а, только защитить напр мутексом

И локать мьютекс дважды. Умно!
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #13 : Сентябрь 08, 2018, 07:26 »

И локать мьютекс дважды. Умно!
Да собсно тут и флажком можно обойтись, без мутекса. Псевдокод
Код
C++ (Qt)
void CheckerL::timerEvent( QTimerEvent * )
{
// если получатель сигнала newData еще не сбросил флажок
// то мапа может быть в использовании, пропускаем
// (хотя и маловероятно на интервале 1 сек)
 if  (m_writeFlag) return;
 
// взводим флажок, мапа пишется
 m_writeFlag = true;
 
// строим мапу
BuildMap(m_data);
 
// посылаем сигнал в UI
emit newData(this);
}
 
Получив сигнал newData, UI использует мапу и после этого сбрасывает checker->m_writeFlag, т.е. события таймера могут заполнять ее снова
« Последнее редактирование: Сентябрь 08, 2018, 07:29 от Igors » Записан
sergek
Гипер активный житель
*****
Offline Offline

Сообщений: 862


Мы должны приносить пользу людям.


Просмотр профиля
« Ответ #14 : Сентябрь 08, 2018, 11:03 »

Да собсно тут и флажком можно обойтись, без мутекса.
Интересно, с какими типами переменных такие операции атомарны?
Записан

Qt 5.13.0 Qt Creator 5.0.1
Win10, Ubuntu 20.04
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


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