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

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

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Пауза  (Прочитано 11017 раз)
Hero Sanya
Новичок

Offline Offline

Сообщений: 34



Просмотр профиля
« : Май 20, 2020, 13:26 »

Как ставить функцию, выполняющуюся в потоке, на паузу, при нажатии кнопки?
Я сделал кнопочку, которая собирает данные с полей для ввода и отправляет их в функцию обработки, из неё, в функцию расчёта, в другом потоке(функция очень большая и долго считающая). Мне нужно, чтобы можно было прерывать выполнение этой функции в любой момент (нажимать на паузу). Я даже не представляю, что должно происходить в коде, при нажатии на кнопку "пауза".
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #1 : Май 20, 2020, 14:34 »

Ну если "без затей" то просто sleep в цикле, напр
Код
C++ (Qt)
void CheckPause( void )
while (pauseFlag)
 QThread::sleep(20);
}
 
И повтыкать эту ф-цию в тело длинных расчетов. Ну а кнопочка устанавливает переменную pauseFlag. И, кстати, "прерывать" и "останавливать" не одно и то же
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #2 : Май 20, 2020, 14:57 »

https://code.woboq.org/qt5/include/qt/QtCore/qfuture.h.html#_ZN7QFuture5pauseEv
https://code.woboq.org/qt5/qtbase/src/corelib/thread/qfutureinterface.cpp.html#_ZNK20QFutureInterfaceBase8isPausedEv
https://code.woboq.org/qt5/qtbase/src/corelib/thread/qfutureinterface.cpp.html#_ZN20QFutureInterfaceBase13waitForResumeEv
Записан
Hero Sanya
Новичок

Offline Offline

Сообщений: 34



Просмотр профиля
« Ответ #3 : Май 20, 2020, 16:10 »

Ну если "без затей" то просто sleep в цикле, напр
Код
C++ (Qt)
void CheckPause( void )
while (pauseFlag)
 QThread::sleep(20);
}
 
И по вставлять эту функцию в тело длинных расчетов. Кнопочка устанавливает переменную pauseFlag. И, кстати, "прерывать" и "останавливать" не одно и то же

Так, то есть, обернуть всю функцию с расчётами в кокон из while(pauseFlag)? На само деле я не знаю что такое pauseFlag. Я к тому, что, нужны ли там библиотеки? И я так подразумеваю, что в итоге пауза будет ставится не сразу по нажатию кнопки, а пока она сигнал не поймает?
Записан
Hero Sanya
Новичок

Offline Offline

Сообщений: 34



Просмотр профиля
« Ответ #4 : Май 20, 2020, 16:12 »

О май гад. Что это за гиганский h. файлы?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #5 : Май 21, 2020, 10:47 »

Так, то есть, обернуть всю функцию с расчётами в кокон из while(pauseFlag)?
Наоборот, вставить эту ф-цию в длинные расчеты, напр в тело цикла
На само деле я не знаю что такое pauseFlag.
Обычная переменная (лучше член класса) которую Вам надо завести
Я к тому, что, нужны ли там библиотеки?
Нет
И я так подразумеваю, что в итоге пауза будет ставится не сразу по нажатию кнопки, а пока она сигнал не поймает?
Да, будет считать пока дело не дойдет до ф-ции

Танки вперед Улыбающийся Я всегда считал футуру бездарной, ну может я не прав. Можно пример (пседокод, словами, как угодно) как ее задействовать в данном случае? Спасибо
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #6 : Май 21, 2020, 11:16 »

Я бы не стал использовать циклы со слипом, ибо это костыльное решение. На счет QFuture ничего сказать не могу, но я не уверен, что там так все просто, твой код должен поддерживать приостановку (если не прав, поправьте, самому лень читать доки).
Я поступил бы по-другому - реализовал расчеты так, чтобы можно было либо безболезненно остановить их, сохранив промежуточные результаты. Если это никак не получается, то хотя бы сделать все по-нормальному, используя QMutex, QSemaphore, QWaitCondition.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #7 : Май 21, 2020, 12:01 »

...ибо это костыльное решение.
Да. Зато "дешево, удобно, практично".

Я поступил бы по-другому - реализовал расчеты так, чтобы можно было либо безболезненно остановить их, сохранив промежуточные результаты. Если это никак не получается, ..
Такая возможность выпадает редко. Обычно расчет наструячит массу своих данных, объектов и.т.п. и сохранить/восстановить этот "контекст" оказывается неподъемным.

..то хотя бы сделать все по-нормальному, используя QMutex, QSemaphore, QWaitCondition.
Как только Вы попробуете привести пример "по-нормальному" - все окажется очень непросто Улыбающийся
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #8 : Май 21, 2020, 18:42 »

Я поступил бы по-другому - реализовал расчеты так, чтобы можно было либо безболезненно остановить их, сохранив промежуточные результаты. Если это никак не получается, то хотя бы сделать все по-нормальному, используя QMutex, QSemaphore, QWaitCondition.

И это ровно то что делает QFutureInterface=)
На самом деле надо попедалировать рассылку Qt на тему того чтобы переименовать его в QPromise и таки задокументировать (это уже всплывало ~месяц назад но как всегда заглохло)
Записан
Hero Sanya
Новичок

Offline Offline

Сообщений: 34



Просмотр профиля
« Ответ #9 : Май 21, 2020, 22:42 »

Так. В общем, я сделал три кнопки:Пауза, продолжить и старт. Старт запускает программу и она сидит в цикле(пока, не тру), если паузы так и не произошло, то просто выйдет из него поставив тру. По пути она будет считывать файл в котором будет лежать ключ(ну просто код), собственно этот код изменяется нажатием пауза. То есть пауза, просто берёт файл, переписывает его содержимое в единичку(можно сказать что это ключ для паузы). собственно, когда глобальная функция прочтёт из файла единицу, она войдёт в замкнутый цикл.На всякий случай я там оставил таймер. там тоже происходит чтение файла и если была нажата кнопка продолжить, файл пере пишется ну, на любую другую цифру(например 2). То есть файлом, можно игнорировать такую вещь, как потоки и передавать послания в любые другие потоки или основной. Можете назвать это костылём, но это работает идеально, так ещё и оставляет возможность для модификаций, например для сериализации кода(что пригодится для сохранения и загрузки).

В итоге: Пауза и продолжить, просто переписывают по нажатию кнопки текст в файле, а циклы являются скажем так, контрольными точками или чекпоинтами.
Записан
Hero Sanya
Новичок

Offline Offline

Сообщений: 34



Просмотр профиля
« Ответ #10 : Май 21, 2020, 23:01 »

Если кому нужно, я приложу своё решение проблемы с паузой. Однако, тут я всё ещё не знаю, как реализовать неактивные кнопки(НО я думаю, это тема другой..эмм. темы). Так же, я считаю. что тут единственная дыра, это когда пользователь нажмёт на кнопку во время чтения из файла. С другой стороны, для выхода из паузы, можно придумать один единственный код: какие нибудь 8888, да он пропустит одну итерацию в цикле, но в итоге всё ровно продолжит программу.
.h
Код:
#ifndef THREE_H
#define THREE_H
void start(bool stoper);
#endif // THREE_H
.Cpp
Код:
#include "mainwindow.h"
#include <math.h>

#include <iostream>
using namespace std;

#include <thread> //две библиотеки,
#include <chrono> //для потоков
#include "three.h"
#include <stdlib.h>

void one(bool stoper){
    int i=0;
    char str[10];
    int n=0;
    FILE* fan;


    while(stoper==false){
    cout<<"i="<<i<<endl; i++;
    this_thread::sleep_for(chrono::milliseconds(1500));

      fan=fopen("test.txt","r");
      while(!feof (fan)) {
      if (fgets(str, 10, fan))
       n = atoi(str);
 cout<<"s="<<str<<endl;
 this_thread::sleep_for(chrono::milliseconds(1000));
 cout<<"n="<<n<<endl;
 this_thread::sleep_for(chrono::milliseconds(1000));
    }

  this_thread::sleep_for(chrono::milliseconds(3000));
     if(n==1){
         while(n==1){
             cout<< "pause" << endl;
             this_thread::sleep_for(chrono::milliseconds(1000));
             rewind(fan);
             while(!feof (fan)) {
                 cout<< "@";
             if (fgets(str, 10, fan))
              n = atoi(str);
             cout<<"n in pause="<< n << "pause" << endl;
         }
         }
         cout<< "continue" << endl;
         this_thread::sleep_for(chrono::milliseconds(200));
         }
     //stoper=true;
    }
fclose(fan);
}



void start(bool stoper){
thread th(one,stoper);
th.detach();
}


MainWindow::MainWindow(QWidget *parent):
Код:
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    FILE* fn;
    fn=fopen("test.txt", "w");
    fprintf(fn,"111");
    fclose(fn);
}
Кнопки(Да, я там использовал глобальную переменную, которую и хотел изменять, её по сути можно удалить):
Код:
bool stoper=false;

void MainWindow::on_pushButton_clicked()//старт
{
    if(stoper==false)
    start(stoper);
}

void MainWindow::on_pushButton_2_clicked()//пауза
{   FILE* f;
    f=fopen("test.txt","w");

    if(f == NULL)
        {
            printf("не могу открыть файл '%s'", "test.txt");
        } else


        fprintf(f,"1");
    fclose(f);
}

void MainWindow::on_pushButton_3_clicked()//продолжить
{
    FILE* f;
        f=fopen("test.txt","w");

        if(f == NULL)
            {
                printf("не могу открыть файл '%s'", "test.txt");
            } else


            fprintf(f,"32");
        fclose(f);
}
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #11 : Май 21, 2020, 23:02 »

>То есть файлом, можно игнорировать такую вещь, как потоки и передавать послания в любые другие потоки или основной

Угу. А про кеширование файловой системы ты не слышал? Обрабатываешь ситуацию, если файл пустой? А если двое сразу запишут в него что-нибудь?
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
Hero Sanya
Новичок

Offline Offline

Сообщений: 34



Просмотр профиля
« Ответ #12 : Май 21, 2020, 23:45 »

>То есть файлом, можно игнорировать такую вещь, как потоки и передавать послания в любые другие потоки или основной

Угу. А про кеширование файловой системы ты не слышал? Обрабатываешь ситуацию, если файл пустой? А если двое сразу запишут в него что-нибудь?
Это просто пример паузы. Переписывать файл могут только пауза и продолжить(просто в этом примере они активны одновременно, что ошибка).
На счёт игнорирования, я имел ввиду, что можно организовать общение потоков через файловую систему.
Да, тут нету обработок на случай если файл пустой, просто я в маинвиндовс, сразу создаю файл заполненным. Другое дело. если кто то целенаправленно захочет удалить или переписать файл(ну а это ровно тоже самое, если переписать любой файл программы).
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #13 : Май 22, 2020, 10:21 »

То есть файлом, можно игнорировать такую вещь, как потоки и передавать послания в любые другие потоки или основной. Можете назвать это костылём, но это работает идеально, так ещё и оставляет возможность для модификаций, например для сериализации кода(что пригодится для сохранения и загрузки).
Обычно подобные городушки лепятся для процессов (впрочем и там это плохо), но для потоков, где память общая, зачем же читать файл в цикле?
Цитировать
— Но зачем же брить яйца наголо, поручик?
— Дикари-с.

И это ровно то что делает QFutureInterface=)
Не слышал о таком, но рискну утверждать что для данной задачи (т.е. (при)остановить один но длинный расчет) он ничем не поможет. Т.к. задача по своей природе "интрузивна", т.е. ф-ция останова должна быть внедрена в код расчетов, сделать это чисто "извне" невозможно.

Вообще затрудняюсь вспомнить случай когда мне нужно было чего-то там "подсматривать" при параллельном выполнении. Индикатор - да, а вот тот же (при)останов - крайне редко. Обычно нужно выжать скорость, поэтому все эти футуры, промисы и.т.п. мне без надобности.
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #14 : Май 22, 2020, 10:40 »

Соглашусь с Igors, для возможности останова должен быть модифицирован код. А любое добавление проверок или индикации в код расчета замедлит его в разы. Если возможно, можно разбить расчет на несколько этапов и делать проверки между этими этапами. Соответственно, в данном случае можно будет и сохранить текущее состояние расчетов.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


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