На главную
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
Страницы: (4) 1 [2] 3 4  все  ( Перейти к последнему сообщению )  
> Разгрузка CPU в потоке
    Цитата JoeUser @
    Я загуглил, на SO ответили однозначно, что нужен велосипед (You can't, and must redesign), т.к. conditial variable только одно состояние отслеживает.
    На условной переменной ты можешь собрать произвольной сложности условие. Получить аналог WaitForMultipleObjects() несложно.
    Одни с годами умнеют, другие становятся старше.
      К слову, зачем тебе там нужен WaitForMultiplyObjects ? Почему сам цикл не переделать как то так?
      ExpandedWrap disabled
        while(!BreakFlag)
        {
            std::unique_lock<std::mutex> lk(cv_m);
            if(cv.wait_for(lk, std::chrono::milliseconds(100000), [](){return ReadyFlag;}))
            { //! ReadyFlag is true
                doSomething();
            }
            else
           { //! timeout
           }
        }


      Добавлено
      Цитата JoeUser @
      А программа всего лишь что и делает в фоне - только мониторит состояние фискального аппарата (если я не ошибаюсь по COM-порту).

      К слову:
      Монитор
      Очень познавательная статья.

      Добавлено
      Ну или еще для любителей велосипедов решение на семафорах, то что судя по всему предлагал ЫукпШ: https://habr.com/ru/post/261273/
        Цитата shm @
        Вопрос странный. Поток может быть в 2 состояниях: активным и в спячке. В спячке поток ожидает событий для пробуждения. События могут быть сгенерированы в пользовательском коде (в других потоках) или ОС как ответ на ожидание каких-то аппаратных событий, например, тех же данных на COM порту.


        Ну попробую еще раз объяснить ... :wall: Как-то недавно Киля мне порекомендовал либу Interception. Процесс чтения данных там можно осуществлять двумя функциями (вернее ожидание данных на устройстве):

        1) interception_wait
        2) interception_wait_with_timeout

        Так вот первую функцию я не могу использовать по одной простой причине - пока она бесконечно висит я не могу завершить поток нормальным способом если вдруг мне это надо. Поэтому я использую вторую функцию с указанием тайм аута. Нет данных - пошла очередная итерация цикла. А вот в ней я уже могу анализировать BreakFlag. Если увижу что взведен - выхожу из цикла и завершаю поток.

        Советовали и мьютексы, и семафоры, и cоndition_variable. Но куда тут их всунуть? Кто извне (из другого треда) будет их забирать-отпускать?

        А вот теперь, допустим, другая похожая задача.

        Я должен осуществлять другую операцию в потоке - вместо interception_wait_with_timeout ... что нибудь типа std::filesystem::exists("helloworld.txt"). И если файл найден - удалять. Делать пока поток не будет прерван. Если sleep в цикл не поставлю - "комп через час-два закипит"?
        Мои программные ништякиhttps://majestio.info
          JoeUser, давай пройдёмся по теории. Её тут уже коснулись, но систематизировать не помешает.
          Итак, существует два варианта реакции на изменившиеся окружающие условия: либо тебе об этом кто-то сообщает, и тогда нет проблем, вешаешься на сигнал и ждёшь; либо никаких нотификаций не предусмотрено, тогда у тебя остаётся вариант пуллить это событие самостоятельно. Второй вариант, вообще говоря, сводится к первому, надо лишь самому реализовать эту нотифю, вопрос лишь в том, стоит ли. Но как бы там ни было, в первом случае задача решена до тебя, и этот вариант уже рассматривался выше, но по ходу это не тот вариант, который тебя интересует, так что второй.
          Любой пуллинг основан на периодическом опросе. Вопрос о его реализации, думаю, стоит не в том ключе, мол, как это сделать, а в том, мол, как это сделать эффективно. Wound тебе предложил условные переменные, что даёт половину решения, основанное на нотификациях, условия которых ты сам же и определяешь. Не самое удобное, возможно, зато универсальное: написал один раз и забыл. Вторая половина упирается в то, что нельзя ничего сказать о величине периода опроса, т.к. это сильно зависит от характера процесса, чьё состояние опрашивается. И от него же зависит формулировка условия для нотификации.
          К примеру, опрос своего файлика ты можешь оформить просто как
          ExpandedWrap disabled
            std::condition_variable cv;
            std::mutex cv_m;
             
            using namespace std::chrono_literals;
             
            /* ... */
            std::unique_lock<std::mutex> lk(cv_m);
            cv.wait_for(lk, 1s, []{ return std::filesystem::exists("helloworld.txt"); });
          Как бы с этим проблем нет. Точное время опроса и точных критериев нотификации тебе никто в общем случае не подскажет.
          Проблема же всплывает, если тебе нужно отслеживать несколько нотификаций сразу и по-разному на них реагировать. Ну так выше я уже писал, что условие ты можешь поставить любое. Напиши что-то типа
          ExpandedWrap disabled
            std::atomic<bool> break_event = false;
            /* ... */
            cv.wait_for(lk, 1s, []{ return std::filesystem::exists("helloworld.txt") || break_event; });
          И снова никто не подскажет общего случая, условия могут быть самыми разными.

          P.S. В принципе при таком подходе уже и таймаут не нужен.
          Сообщение отредактировано: Qraizer -
          Одни с годами умнеют, другие становятся старше.
            Цитата JoeUser @
            Советовали и мьютексы, и семафоры, и cоndition_variable. Но куда тут их всунуть? Кто извне (из другого треда) будет их забирать-отпускать?

            А ранее ты сам же на этот вопрос и отвечаешь :D :
            Цитата JoeUser @
            Так вот первую функцию я не могу использовать по одной простой причине - пока она бесконечно висит я не могу завершить поток нормальным способом если вдруг мне это надо. Поэтому я использую вторую функцию с указанием тайм аута. Нет данных - пошла очередная итерация цикла. А вот в ней я уже могу анализировать BreakFlag. Если увижу что взведен - выхожу из цикла и завершаю поток.

            На сколько я понял у тебя это как раз взаимосвязано. Там где тебе нужно поменять флаг - там ты пишешь notify_one/notify_all, там где у тебя флаги проверяются - ты пишешь wait/wait_for/wait_until/etc.
            У тебя по условию задачи - есть сигнал и есть его обработчик. Сейчас ты это все разруливаешь флагами, у тебя в каком то месте флагу присваивается значение true, а в другом месте этот самый флаг на значение true проверяется. Тебе в том месте - где присваивается значение флагу true - нужно изменить условие(поменять значение на true своему флагу например) и вызвать notify, а в том месте - где у тебя флаг проверяется тебе нужно заюзать wait_for. Что тут непонятного то? :-?
            Сообщение отредактировано: Wound -
              Qraizer, да, именно о пуллинге идет речь. потому как не от каждой операционной системы и не по каждому состоянию получишь какое либо сообщение.
              Вот я накидал пример того, о чем спрашиваю:
              ExpandedWrap disabled
                #if __cplusplus < 201703L
                #error "C++17 podavai suda!"
                #endif
                 
                #include <filesystem>
                #include <iostream>
                #include <string>
                #include <thread>
                #include <atomic>
                 
                using namespace std::chrono_literals;
                 
                std::atomic<bool> BreakFlag = ATOMIC_FLAG_INIT;
                std::atomic<bool> TerminateFlag = ATOMIC_FLAG_INIT;
                std::string FileName = "C:/Temp/helloworld.txt";
                 
                void ThreadFunc() {
                  do {
                    if (BreakFlag) break;
                    try {
                      if (std::filesystem::exists(FileName)) std::filesystem::remove(FileName);
                    } catch (...) {}
                    // std::this_thread::sleep_for(1ms); // Если не раскоментировать - будет жесть, 17-20% жрет CPU!!!
                  } while (true);
                  TerminateFlag = true;
                }
                 
                int main() {
                  std::string str;
                  std::thread Thread(ThreadFunc);
                  Thread.detach();
                  std::cout << "Type \"Exit\" to exit..." << std::endl;
                  do {
                    std::cin >> str;
                  } while (str != "Exit");
                  BreakFlag = true;
                  while (!TerminateFlag) std::this_thread::yield();
                  std::cout << "Done." << std::endl;
                  return 0;
                }

              Прога элементарная. Ждет написания в консоли слова Exit и нажатие [Enter]. А пока ждет - работает. А именно ищет файл "C://Temp//helloworld.txt" и если находит - грохает его.

              Перепишите мне с мьютексами, семафорами, или condition_variable чтобы стало лучше/правильнее. И что именно станет правильнее и лучше?

              ЗЫ: Если раскоментить std::this_thread::sleep_for(1ms) - загрузка CPU у меня 0%
              Мои программные ништякиhttps://majestio.info
                Вот например есть какой то синтетический пример, показывающий как это все работает: https://ru.cppreference.com/w/cpp/thread/co...riable/wait_for
                ExpandedWrap disabled
                  #include <iostream>
                  #include <atomic>
                  #include <condition_variable>
                  #include <thread>
                  #include <chrono>
                   
                  std::condition_variable cv;
                  std::mutex cv_m;
                  std::atomic<int> i = ATOMIC_VAR_INIT(0);
                   
                  void waits(int idx)
                  {
                      std::unique_lock<std::mutex> lk(cv_m);
                      if(cv.wait_for(lk, std::chrono::milliseconds(idx*100), [](){return i == 1;}))
                          std::cerr << "Thread " << idx << " finished waiting. i == " << i << '\n';
                      else
                          std::cerr << "Thread " << idx << " timed out. i == " << i << '\n';
                  }
                   
                  void signals()
                  {
                      std::this_thread::sleep_for(std::chrono::milliseconds(120));
                      std::cerr << "Notifying...\n";
                      cv.notify_all();
                      std::this_thread::sleep_for(std::chrono::milliseconds(100));
                      i = 1;
                      std::cerr << "Notifying again...\n";
                      cv.notify_all();
                  }
                   
                  int main()
                  {
                      std::thread t1(waits, 1), t2(waits, 2), t3(waits, 3), t4(signals);
                      t1.join(); t2.join(), t3.join(), t4.join();
                  }
                  Цитата Wound @
                  На сколько я понял у тебя это как раз взаимосвязано. Там где тебе нужно поменять флаг - там ты пишешь notify_one/notify_all, там где у тебя флаги проверяются - ты пишешь wait/wait_for/wait_until/etc.

                  Киля, вон я выше накидал тестовую прогу. К тебе тож просьба - перепиши ее с твоими wait/async/future, ну как ты советовал.

                  Добавлено
                  Цитата Wound @
                  Вот например есть какой то синтетический пример

                  Мой перепиши, плс, то что мне надо.
                  Мои программные ништякиhttps://majestio.info
                    Цитата JoeUser @
                    Прога элементарная. Ждет написания в консоли слова Exit и нажатие [Enter]. А пока ждет - работает. А именно ищет файл "C://Temp//helloworld.txt" и если находит - грохает его.

                    Перепишите мне с мьютексами, семафорами, или condition_variable чтобы стало лучше/правильнее. И что именно станет правильнее и лучше?

                    А причем тут эта прога и то что ты хочешь? Ты пишешь - как мне усыпить поток, чтоб он мне CPU не жрал. И просишь переписать твой пример - где у тебя усыплением потока и не пахнет, где один поток файлы ищет, а второй ждет пока ему Exit не напишут. Как ты свой пример перепишешь с WaitForMultiplyObjects ? Я не понимаю твоего примера.

                    Добавлено
                    Цитата JoeUser @
                    Мой перепиши, плс, то что мне надо.

                    Не могу. У тебя приведенный пример, противоречит тому, что ты тут две страницы пояснял. Я не знаю что тебе тут переписать? В примере приведеном тобою главный поток ждет, пока ему не напишут Exit, а потом тупо выходит.
                    Или тебе нужно застопорить поток там, где у тебя std::this_thread::yield(); ?
                    Тогда как то так будет:
                    ExpandedWrap disabled
                      #include <filesystem>
                      #include <iostream>
                      #include <string>
                      #include <thread>
                      #include <atomic>
                      #include <condition_variable>
                       
                      using namespace std::chrono_literals;
                       
                      bool BreakFlag = ATOMIC_FLAG_INIT;
                      bool TerminateFlag = ATOMIC_FLAG_INIT;
                      std::string FileName = "C://Temp//helloworld.txt";
                       
                       
                      std::condition_variable cv;
                      std::mutex cv_m;
                       
                       
                      void ThreadFunc() {
                          do {
                              if (BreakFlag)
                              {
                                  cv.notify_one();
                                  break;
                              }
                       
                              try {
                                  if (std::filesystem::exists(FileName))
                                      std::filesystem::remove(FileName);
                              }
                              catch (...) {}
                              // std::this_thread::sleep_for(1ms); // Если не раскоментировать - будет жесть, 17-20% жрет CPU!!!
                          } while (true);
                          TerminateFlag = true;
                      }
                       
                      int main() {
                          std::string str;
                          std::thread Thread(ThreadFunc);
                          Thread.detach();
                          std::cout << "Type \"Exit\" to exit..." << std::endl;
                          do {
                              std::cin >> str;
                          } while (str != "Exit");
                       
                          BreakFlag = true;
                       
                       
                          while (true)
                          {
                              std::unique_lock<std::mutex> lk(cv_m);
                              if (cv.wait_for(lk, std::chrono::seconds(1), [=]() {return TerminateFlag; }))
                              {
                                  break;
                              }
                          }
                       
                          std::cout << "Done." << std::endl;
                          return 0;
                      }
                      Цитата Wound @
                      Ты пишешь - как мне усыпить поток

                      Да ё-мое! Ну почитай ты название топика! :( Я спрашивал что нужно чтобы прога не жрала CPU без надобности и только. А то что я усыпляю его на доли секунды - это как одно из решений. Я не спрашиваю как его полностью усыпить!

                      Добавлено
                      Цитата Wound @
                      Я не понимаю твоего примера.

                      Я старался! :no-sad:
                      Мои программные ништякиhttps://majestio.info
                        Цитата JoeUser @
                        Да ё-мое! Ну почитай ты название топика! :( Я спрашивал что нужно чтобы прога не жрала CPU без надобности и только. А то что я усыпляю его на доли секунды - это как одно из решений. Я не спрашиваю как его полностью усыпить!

                        В каком месте у тебя прога жрет CPU без надобности?
                        Ты в первом посту пишешь:
                        Цитата JoeUser @
                        В одной из программ, которую подогнали разработчики, постоянная загрузка CPU висит в районе 25%. И это на Core i3 2.5GHz. А программа всего лишь что и делает в фоне - только мониторит состояние фискального аппарата (если я не ошибаюсь по COM-порту). Все мои попытки убедить разработчиков, что это нонсенс, упираются в "стену". Отвечают что-то в роде "нам важно, чтобы система с фискальным аппаратом работала без задержек, мы лучше знаем" :wall: Я подозреваю, что залепили в своем коде что-то в виде:

                        Где в твоем примере мониторинг состояния, любого?
                          Цитата Wound @
                          Тогда как то так будет:

                          И улучшений - нуль! :lol:
                          Если слип-задержку не раскоментить - как жрала прога 17% CPU, так и жрет. Это сразу было видно по твоему коду. Но я проверил на всяк случай:

                          user posted image
                          Мои программные ништякиhttps://majestio.info
                            Цитата JoeUser @
                            А именно ищет файл "C://Temp//helloworld.txt" и если находит - грохает его.

                            Перепишите мне с мьютексами, семафорами, или condition_variable чтобы стало лучше/правильнее. И что именно станет правильнее и лучше?

                            Эта задача правильнее и лучше не решается.
                            Ты не можешь подписаться в системе на такое событие - "наличие такого-то файла".
                            А вот следить за изменениями в указанной директории вроде можно.
                            (я этого не делал, поэтому определённо сказать не могу).
                            тут
                            Поэтому заснуть потоком, но ждать событие "изменения в папке" - можно.
                            ---
                            И потом - что значит "правильнее и лучше" ?
                            Это всё субъективно.
                            Для того, что ты показал, сделанное достаточно.
                            Но если бы ты задавал имя файла для поиска и уничтожения
                            в окошке эдита, а потом жал на кнопку, тогда надо:
                            1. Заснуть потоком на Wait.
                            2. Ждём 2 события - Exit и Work.
                            3. Если завершаем приложение, взводим Exit
                            4. Если жмём на кнопку "Уничтожить указанный файл" - значит
                            взводим Work. Дальше начинается поиск файла в папке и всех вложенных папках
                            и уничтожение его. Потом снова засыпаем.
                            Сообщение отредактировано: ЫукпШ -
                            Подпись была выключена в связи с наложенным заземлением.
                              Цитата Wound @
                              Где в твоем примере мониторинг состояния, любого?

                              Вот тут:
                              ExpandedWrap disabled
                                if (std::filesystem::exists(FileName))
                              Мои программные ништякиhttps://majestio.info
                                Цитата ЫукпШ @
                                Ты не можешь подписаться в системе на такое событие - "наличие такого-то файла".

                                Ну в разных ОС по разному, в Линухе, к примеру, это можно решить с помощью inotify.
                                Там много чего можно отслеживать, в том числе и появление файла, и его закрытие после записи.
                                Мои программные ништякиhttps://majestio.info
                                1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
                                0 пользователей:
                                Страницы: (4) 1 [2] 3 4  все


                                Рейтинг@Mail.ru
                                [ Script Execution time: 0,2076 ]   [ 15 queries used ]   [ Generated: 9.08.20, 16:51 GMT ]