На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
  
> Разгрузка CPU в потоке
    Всем привет!

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

    ExpandedWrap disabled
      do {
        if (BreakFlag) break;
        if (!ReadyFlag) continue;
        doSomething();
        ...
      } while(true);

    Ну Ктулху - им судья! :no-sad: А вот теперь мне в своей проге понадобилось сделать что-то подобное. Понимаю, что идеальным вариантом можно было бы использовать WaitForMultipleObjects. Но для кросс-платформенной реализации такой вариант - не выход. А похожей блокирующей функции у меня в распоряжении нет. Есть только флаг готовности. Вот собственно вопрос - на сколько я повторю ситуацию, описанную в начале поста, если это реализую подобным образом, но с усыплением потока? Что-то типа:

    ExpandedWrap disabled
      do {
        if (BreakFlag) break;
        if (!ReadyFlag) {
          std::this_thread::sleep_for(1ms);
          continue;
        }
        doSomething();
        ...
      } while(true);


    Какие варианты есть лучше?
      Цитата JoeUser @
      Какие варианты есть лучше?

      Лучше тебе предлагали в прошлой теме, но ты их принял в штыки, а оппонентов выставил дураками. :-?
      Вангую тут будет ровно тоже самое.
        Если ты про тему "Распараллеливание выполнения без блокировок", то там акцент был не про сабж, а скорее о параллельном доступе к данным.

        Ну а твой совет типа:

        Цитата Wound @
        1) Вместо std::thread - используй std::future в связке с async (это следует делать в 95% случаях, по крайней мере так советует Майерс, и я ему верю, хотя некоторые не согласны с этим утверждением, но все же) - потому что std::thread имеют кучу подводных камней(читай Майерса)


        Я вообще не пойму как использовать для опроса устройства. На каждое считывание запускать заново поток? И что это даст?
        И второй момент, а как мне прервать такой поток, если ты мне далее предлагаешь

        Цитата Wound @
        2) Вместо std::atomic<ololo> flag - используй conditial variables.

        Мне ведь два состояния нужно отслеживать - чтение и прерывание цикла чтения. Я загуглил, на SO ответили однозначно, что нужен велосипед (You can't, and must redesign), т.к. conditial variable только одно состояние отслеживает.
          Цитата JoeUser @
          .. Есть только флаг готовности... Что-то типа:

          ExpandedWrap disabled
            do {
              if (BreakFlag) break;
              if (!ReadyFlag) {
                std::this_thread::sleep_for(1ms);
                continue;
              }
              doSomething();
              ...
            } while(true);


          Какие варианты есть лучше?

          В качестве флагов можно использовать семафоры.
          Которые есть и у Виндус, и у Юникс.
          Значит, можно сделать до некоторой степени аналог WaitForMultipleObjects.
          Те сделать функцию, которая ждёт много семафоров.
          И по включению каждого вызывает конкретный обработчик.
          Либо использовать кросс-платформенную библиотеку.
          Где всё это должно быть.
          Сообщение отредактировано: ЫукпШ -
            Цитата JoeUser @
            Какие варианты есть лучше?

            Что мешает читать из COM порта с таймаутом? Как данные придут, то функция сразу вернет управление.
            Второй вариант: использовать асинхронное API для работы с COM портом. Бонус: не нужен даже доп. поток.

            Добавлено
            По первому варианту SetCommTimeouts в помощь. Если прямо по байту хочешь вычитывать, то ReadIntervalTimeout ставишь в 1. ReadTotalTimeoutConstant во что-нибудь адекватное, чтобы не завис поток, если данных нет.

            Добавлено
            По второму тоже примеров в сети куча. Смысл в том, что ты будешь висеть на WaitForMultipleObjects пока не придут данные.

            Добавлено
            Цитата JoeUser @
            Отвечают что-то в роде "нам важно, чтобы система с фискальным аппаратом работала без задержек, мы лучше знаем"

            Вызов ClearCommError в бесконечном цикле никак не улучшит отклик.

            Добавлено
            Цитата JoeUser @
            Но для кросс-платформенной реализации такой вариант - не выход.

            boost::asio, только за неимением возможности установить таймаут на порт у тебя нет альтернатив, кроме как использовать асинхронные функции
            Сообщение отредактировано: shm -
              Цитата JoeUser @
              Я вообще не пойму как использовать для опроса устройства. На каждое считывание запускать заново поток? И что это даст?
              И второй момент, а как мне прервать такой поток, если ты мне далее предлагаешь

              Во первых твоя задача не ясна. Я лично вообще не понимаю что ты делаешь. Ты привел кусок кода - и говоришь: как мне его нужно переписать, чтоб было правильно. Из твоего кода ясно что у тебя есть два флага - флаг готовности и флаг завершения программы.
              За что отвечает флаг готовности? Флаг готовности для чего? Как он взаимосвязан с остальной логикой? Может быть этот флаг означает что очередь не пуста? Или он означает что произошло какое то событие? События реализуются с помощью conditional_variable, ну как вариант, у них есть свои достоинства и недостатки. Помимо conditional_variable, можно использовать get_future().wait/std::promise::set_value, но эта штука одноразовая, в отличии от CV.
              Еще ты можешь получить хендл потока std::thread::native_handle() и юзать WaitForMultiplyObjects.

              Например какой то пример эмуляции WaitForMultiplyObjects:
              http://coliru.stacked-crooked.com/a/1dfb87728994b184
              ExpandedWrap disabled
                #include <iostream>
                #include <vector>
                #include <thread>
                #include <future>
                #include <chrono>
                 
                const int TIME_BETWEEN_POLLS_MS = 50;
                 
                // Wait (sleep) between polls until a task is finished then return index.
                template <typename Iterator>
                Iterator finishingThread(Iterator first, Iterator last) {
                    auto it = first;
                    auto status = std::future_status::timeout;
                    while (status != std::future_status::ready) {
                        if (++it == last) {
                            it = first;
                        }
                        status = it->wait_for(std::chrono::milliseconds(TIME_BETWEEN_POLLS_MS));
                    }
                    return it;
                }
                 
                // Example task function that sleeps for specified time and returns thread id.
                std::thread::id sleepFor(int millisec) {
                    std::this_thread::sleep_for(std::chrono::milliseconds(millisec));
                    std::cout << "Terminating thread with id: " << std::this_thread::get_id() << std::endl;
                    return std::this_thread::get_id();
                }
                 
                int main() {
                    // Create three separate tasks.
                    std::packaged_task<std::thread::id(int)> task1{sleepFor},
                                                             task2{sleepFor},
                                                             task3{sleepFor};
                 
                    // Store futures.
                    std::vector<std::future<std::thread::id>> futures;
                    futures.push_back(task1.get_future());
                    futures.push_back(task2.get_future());
                    futures.push_back(task3.get_future());
                 
                    // Run tasks on separate threads.
                    std::vector<std::thread> tasks;
                    tasks.emplace_back(std::move(task1), 1500);
                    tasks.emplace_back(std::move(task2), 500);
                    tasks.emplace_back(std::move(task3), 1000);
                 
                    auto it = finishingThread(std::begin(futures), std::end(futures));
                 
                    std::cout << "We have result of the task that finished first!" << std::endl;
                 
                    // Join threads.
                    for (auto& t : tasks) {
                        t.join();
                    }
                 
                    std::cout << "Winner result: " << it->get() << std::endl;
                }
              Сообщение отредактировано: Wound -
                Цитата ЫукпШ @
                В качестве флагов можно использовать семафоры.

                А чем хуже std::atomic?

                Добавлено
                shm, сорь! Чтение из COM-порта я в начале привел для примера. А так я работаю с USB с помощью либы, которую мне присоветовал Киля. Там есть хорошая функция interception_wait_with_timeout и она решает мою проблему (т.к. в глубине либы она завязана на WaitForMultiplyObjects с тайм аутом).
                У меня же был вопрос более общий - как отдавать кванты вычислений не привязываясь к API Win32 если используется неблокирующая обработка "любого толка"?
                  Цитата JoeUser @
                  Цитата ЫукпШ @
                  В качестве флагов можно использовать семафоры.

                  А чем хуже std::atomic?

                  Это не о том - насколько я понимаю.
                  я не про атомарность говорю, а отвечаю на вопрос по теме - как экономить время.
                  Для этого надо работать по событиям.
                  У тебя 2 события в цикле - "выход" и "работа".
                  Значит надо остановить поток и ждать 2 объекта, я предлагаю семафоры.
                  -----
                  Семафор - это такой объект ядра, который может остановить поток.
                  И этот поток перестанет тратить процессорное время вообще.
                  Кроме того, у него имеется полезное свойство - если будет
                  получено несколько (много) уведомлений о событии, в то время
                  как текущее событие всё ещё обрабатывается, ни одно
                  из уведомлений не будет утеряно.
                  Рабочий поток будет разбужен семафором столько раз, сколько
                  надо.
                    Цитата Wound @
                    Во первых твоя задача не ясна. Я лично вообще не понимаю что ты делаешь.

                    А как можно начинать советовать, если не выяснил? :blink:
                      Цитата JoeUser @
                      А как можно начинать советовать, если не выяснил?

                      А я ниче и не советовал. Просто посетовал, что опять будешь всех дураками выставлять :-?
                      Сообщение отредактировано: Wound -
                        Цитата ЫукпШ @
                        Значит надо остановить поток и ждать 2 объекта, я предлагаю семафоры.

                        Я тебя понял! Только тут получается какой-то замкнутый круг ... Вот представь пример. Unix система. Второй поток, который висит "на семафорах" должен распечатать файл в STDOUT, если файл он появился в каталоге. Ну или должен завершиться, если завершается вся программа. Получается, что должен быть еще один поток (третий), который уведомит второй поток, что файл появился. А в нем как разгружать CPU в ожидании?

                        Да, я знаю, что существует интересная либа libevent, которая эмулирует кросс-платформенно систему уведомлений (сообщений). Но вопрос был в другом - как стандартными средствами C++11 и выше разгружать CPU?
                          Скрытый текст
                          Цитата Wound @
                          А я ниче и не советовал. Просто посетовал, что опять будешь всех дураками выставлять

                          Киля, ты всегда рвешься в бой быстрее танка. Начинаешь сразу рубить с плеча, или обижаться. Пойми, я никак не принижаю твои достоинства как программера, и очень часто тебе благодарен. Но я считаю, что ты очень часто спешишь не разобравшись. А ведь не всегда удается задать вопрос так, чтобы непоняток не было вообще ... если вопрос конечно ну не совсем уж тривиальный. Без обид! :)
                            Цитата JoeUser @
                            Unix система. Второй поток, который висит "на семафорах" должен распечатать файл в STDOUT, если файл он появился в каталоге. Ну или должен завершиться, если завершается вся программа. Получается, что должен быть еще один поток (третий), который уведомит второй поток, что файл появился. А в нем как разгружать CPU в ожидании?

                            1 Про выход - если приложение завершается, значит будет вызван
                            деструктор объекта-потока. Из деструктора будет установлен
                            семафор "Exit", а потом ожидание завершения потока (pthread_join).
                            Рабочий поток завершиться по семафору. На случай проблем
                            предусмотрим принудительное уничтожение потока, если будет
                            превышено время допустимого ожидания завершения.

                            2. Если ты что-то там ожидаешь в событийной модели, значит
                            копай доки для твоего случая.
                            Если нет таких событий - тогда никак. Тогда надо ждать в цикле со Sleep-ом.
                            И семафор тоже можно опрашивать в таком цикле.
                            --
                            Кроме того, у Юникса есть функции ожидания - Select, например.
                            Работает с файловыми дескрипторами.
                            Скрытый текст

                            На просторах Сети я узнал про такой финт ушами:
                            - для создания события на выход из цикла был создан pipe и его
                            хэндл тоже был передан Select-у. Для выхода достаточно было
                            послать символ в pipe.


                            Надо заметить, что цикл со Sleep-ом это не криминал.
                            Однако, чем меньше будет таких решений, тем меньше
                            будет бессмысленно истраченного времени.
                            Сообщение отредактировано: ЫукпШ -
                              Цитата JoeUser @
                              А в нем как разгружать CPU в ожидании?

                              Да, я знаю, что существует интересная либа libevent, которая эмулирует кросс-платформенно систему уведомлений (сообщений). Но вопрос был в другом - как стандартными средствами C++11 и выше разгружать CPU?

                              Вот в этом и заключается преимущество подхода на основе conditional variable. Они не нагружают CPU, и реально ждут оповещения(плюс нужно учитывать что случаются ложные пробуждения, но они очень просто лечатся).
                              Т.е. они работают как события и при этом не грузят аппаратный поток, как в случае с флагами. Ровно так же работают промисы, но у них есть одна ложга дегтя, их можно установить только 1 раз, в отличии от conditional variable.


                              Цитата JoeUser @
                              Киля, ты всегда рвешься в бой быстрее танка. Начинаешь сразу рубить с плеча, или обижаться. Пойми, я никак не принижаю твои достоинства как программера, и очень часто тебе благодарен. Но я считаю, что ты очень часто спешишь не разобравшись. А ведь не всегда удается задать вопрос так, чтобы непоняток не было вообще ... если вопрос конечно ну не совсем уж тривиальный. Без обид!

                              Так задай его так, чтоб было понятно на него отвечать.
                              Сообщение отредактировано: Wound -
                                Цитата JoeUser @
                                У меня же был вопрос более общий - как отдавать кванты вычислений не привязываясь к API Win32 если используется неблокирующая обработка "любого толка"?

                                Вопрос странный. Поток может быть в 2 состояниях: активным и в спячке. В спячке поток ожидает событий для пробуждения. События могут быть сгенерированы в пользовательском коде (в других потоках) или ОС как ответ на ожидание каких-то аппаратных событий, например, тех же данных на COM порту.

                                Добавлено
                                Короче мне сама формулировка "отдать квант" непонятна.

                                Добавлено
                                Есть еще такая замечательная функция как std::this_thread::yield(). С помощью нее ты говоришь ОС "моему потоку сейчас делать нечего, пускай поработают другие". При этом, если в ОС есть потоки не в спячке, то им реально будет передано управление. Если таких нет, то ты получишь управление сразу же обратно и как следствие та же загрузка ядра на максимум. Считается, что наличие yield() и подобных функций в коде - это признак кривой архитектуры.
                                Сообщение отредактировано: shm -
                                  Цитата 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 в цикл не поставлю - "комп через час-два закипит"?
                                        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://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 @
                                                Вот например есть какой то синтетический пример

                                                Мой перепиши, плс, то что мне надо.
                                                  Цитата 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:
                                                      Цитата JoeUser @
                                                      Да ё-мое! Ну почитай ты название топика! :( Я спрашивал что нужно чтобы прога не жрала CPU без надобности и только. А то что я усыпляю его на доли секунды - это как одно из решений. Я не спрашиваю как его полностью усыпить!

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

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

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

                                                        user posted image
                                                          Цитата 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))
                                                              Цитата ЫукпШ @
                                                              Ты не можешь подписаться в системе на такое событие - "наличие такого-то файла".

                                                              Ну в разных ОС по разному, в Линухе, к примеру, это можно решить с помощью inotify.
                                                              Там много чего можно отслеживать, в том числе и появление файла, и его закрытие после записи.
                                                                Цитата JoeUser @
                                                                Если слип-задержку не раскоментить - как жрала прога 17% CPU, так и жрет. Это сразу было видно по твоему коду. Но я проверил на всяк случай:

                                                                Потому что у тебя в цикле нет мониторинга чего либо, у тебя там выполняются конкретные действия, а не "мониторит состояние фискального аппарата". Вот ежели бы тебе нужно было мониторить папку на наличие в ней например какого то файла(появился - что то сделать), а до этого момента просто тупо цикл с проверкой - вот тогда это был бы мониторинг.


                                                                Цитата JoeUser @
                                                                Вот тут:
                                                                CollapsedWrap disabledLine numbers off

                                                                if (std::filesystem::exists(FileName))

                                                                :facepalm: И как это условие связано с твоими флагами? :unsure:
                                                                  Цитата ЫукпШ @
                                                                  Ты не можешь подписаться в системе на такое событие - "наличие такого-то файла".

                                                                  В винде точно есть, но не помню и искать лень. Для FreeBSD вроде запилили libinotify. Про OSX не в курсе.

                                                                  Добавлено
                                                                  Цитата Wound @
                                                                  И как это условие связано с твоими флагами?

                                                                  Киля, спасибо за беседу! ;)
                                                                    Цитата JoeUser @
                                                                    Вот тут:
                                                                    CollapsedWrap disabledLine numbers off

                                                                    if (std::filesystem::exists(FileName))

                                                                    Если тебе нужно конкретно файл мониторить, то в принципе тебе выше написали решение:
                                                                    ExpandedWrap disabled
                                                                      #include <filesystem>
                                                                      #include <iostream>
                                                                      #include <string>
                                                                      #include <thread>
                                                                      #include <atomic>
                                                                      #include <condition_variable>
                                                                       
                                                                      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";
                                                                       
                                                                      std::condition_variable cv;
                                                                      std::mutex cv_m;
                                                                       
                                                                      void ThreadFunc() {
                                                                          do {
                                                                              if (BreakFlag) break;
                                                                              try {
                                                                                  std::unique_lock<std::mutex> lk(cv_m);
                                                                                  if (cv.wait_for(lk, std::chrono::seconds(1), [=]() {return std::filesystem::exists(FileName); }))
                                                                                  {
                                                                                      std::filesystem::remove(FileName);
                                                                                      cv.notify_one();
                                                                                  }
                                                                              }
                                                                              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;
                                                                      }


                                                                    Но это тупо. Потому как у тебя нечего оповещать.

                                                                    Добавлено
                                                                    Если тебе нужно конкретно это условие мониторить, то ты можешь написать класс на основе шаблона Observer, и не выносить мозг себе и людям.

                                                                    Добавлено
                                                                    Цитата JoeUser @
                                                                    Киля, спасибо за беседу!

                                                                    Ааа, я понял. Ну и иди в баню. censored Пишешь одно, имея ввиду другое, потом еще фыркаешь. Я это запомню. Давай досвидания.
                                                                    Сообщение отредактировано: Qraizer -
                                                                      Цитата JoeUser @
                                                                      А вот теперь мне в своей проге понадобилось сделать что-то подобное.

                                                                      У мну жсм-шлюз читает/пишет смс-ки в/на ком-порт, достаточно одной таблэтки обычного слипа. нехер мудрствовать, бритва оккама в помощь.
                                                                        Цитата JoeUser @
                                                                        Перепишите мне с мьютексами, семафорами, или condition_variable чтобы стало лучше/правильнее. И что именно станет правильнее и лучше?
                                                                        Они тут по факту не нужны. Но если очень хочется, то можно. Очень хочется – это если хочешь один раз написать и не париться. На WinAPI множественные события ждутся элементарным WaitForMultipleObjects, которая тебе сразу и вернёт тот объект, который отнотифил. Очень удобно. Я бы хотел подобного в std, но коли его нет, можно написать самому: собираешь контейнер предикатов и ожидаешь по нужной комбинации условий, пока не сработают; выходишь с возвратом кортежа результатов предикатов, вызывающий пусть сам анализирует.
                                                                        Конкретно в твоём примере на cv имеет смысл завести лишь BreakEvent. Маловато, проще явно опрашивать.
                                                                          Цитата Qraizer @
                                                                          Они тут по факту не нужны. Но если очень хочется, то можно.

                                                                          В том то и дело, что Gonarh тут правильно упомянул Бритву Оккамы - если профита в данном случае нет, значит нафик и не нужно.

                                                                          Цитата Qraizer @
                                                                          На WinAPI множественные события ждутся элементарным WaitForMultipleObjects, которая тебе сразу и вернёт тот объект, который отнотифил. Очень удобно. Я бы хотел подобного в std

                                                                          Да я в курсе. И в *nix подобного очень не хватает, всякие там libevent + inotify + fsnotify запиливают, чтобы можно было реально засыпать на INFINITY время, но мочь всеж проснуться, а не дергать отдельные флаги или мьютексы.

                                                                          Цитата Qraizer @
                                                                          Конкретно в твоём примере на cv имеет смысл завести лишь BreakEvent. Маловато, проще явно опрашивать.

                                                                          Да нет - не "имеет смысл", а "можно сделать". Но лучше не делать, ибо сам ответил - "проще опрашивать".
                                                                            Цитата Qraizer @
                                                                            Я бы хотел подобного в std

                                                                            Этого и не будет никогда. По крайней мере если коренным образом не определят, что для обеспечения многозадачности С++ - операционная система должна обеспечивать событийную модель взаимодействия. ИМХО, нереально такое ждать.

                                                                            Смысл же WaitForSingleObject/WaitForMultipleObjects в чем? Ядро ОС приостанавливает поток до наступления "одного/одного из" событий (ну или если указано не бесконечное время ожидания) и не отдает ему управление (не ставит в очередь на получение квантов времени). Что мы имеем с std::this_thread::sleep_for? Ядро ОС усыпляет безусловно поток (не ставит в очередь на получение квантов времени) на единицу времени. А что имеем с std::this_thread::yield? Поток вычисления ядром ОС перебрасывается в конец очереди ожидания за получением своего кванта вычислений.

                                                                            И именно ядро усыпляет и пробуждает потоки. И С++ тут никак на этот механизм не может повлиять.

                                                                            Плюс ко всему в последних двух случаях (моей проги) периодически дергается проверка атомарного флага или мьютекса. И если поток не уcыплять - вот тут и ненужные вычисления , ну и бессмысленная загрузка CPU.
                                                                              Смысл yield-а в том, чтобы, имея постоянную полезную работу, время от времени проталкивать фоновые процессы, если они есть. Если у тебя нет полезной работы, а пуллинг – это не полезная работа, это её ожидание, – yield не подходит идеологически.
                                                                              Цитата JoeUser @
                                                                              Этого и не будет никогда.
                                                                              Я бы не был так категоричен. Его можно создать на имеющихся примитивах, притом что архитектурно его спроектировать не так-то просто, поэтому и нет пока, ибо комитет просто не хочет садиться в лужу очередной раз, как это уже случалось из-за непродуманной архитектуры библиотечной фичи. Реализовать полный аналог WaitForMultipleObjects() сложно, и ещё сложнее сделать этот механизм удобным и универсальным. Но конкретно ты конкретно в твоём приложении легко это сделаешь в частном порядке, не затратив существенных усилий.

                                                                              Добавлено
                                                                              Например. Если ожидать "любого из" объектов, то их надо опрашивать одновременно и тут же, как только, захватывать освободившийся. И всё это атомарно. Последнее условие непросто соблюсти, нельзя их опрашивать тупо по очереди, и захватывать первый попавшийся, будет race condition из-за того, что другой поток может быть позади тебя на пару объектов, и у него другой их набор, да ещё и на другом условии их комбинирования. Если нужно ждать "всех сразу", то последовательно тоже нельзя опрашивать и захватывать, будет dead lock по тем же причинам. Обеспечить атомарность можно, только имея контроль над сущностями, а не их представлениями, что вне ядра подсистемы синхронизации, типа как в винды, невозможно, т.к. изначально объекты синхронизации друг с другом никакими условиями не связаны и разными нитками запросто могут использоваться в разных комбинациях и даже поодиночке.
                                                                              Сообщение отредактировано: Qraizer -
                                                                                Цитата JoeUser @
                                                                                Так вот первую функцию я не могу использовать по одной простой причине - пока она бесконечно висит я не могу завершить поток нормальным способом если вдруг мне это надо. Поэтому я использую вторую функцию с указанием тайм аута. Нет данных - пошла очередная итерация цикла. А вот в ней я уже могу анализировать BreakFlag. Если увижу что взведен - выхожу из цикла и завершаю поток.

                                                                                Раз у тебя нет в арсенале неблокирующих функций, то никакие cv тебе не помогут. Читай с небольшим таймаутом и в каждой итерации проверяй флаг выхода, лучше особо ничего не сделаешь. Из очевидных минусов: необходимость доп. потока и завершение будет с задержкой (обычно это не критично).
                                                                                Цитата JoeUser @
                                                                                Я должен осуществлять другую операцию в потоке - вместо interception_wait_with_timeout ... что нибудь типа std::filesystem::exists("helloworld.txt"). И если файл найден - удалять. Делать пока поток не будет прерван. Если sleep в цикл не поставлю - "комп через час-два закипит"?

                                                                                Простое решение - проверять со sleep'ом в цикле. Более сложное - использовать события ОС об изменения файла/каталога в асинхронном варианте. В Виндах это, например, ReadDirectoryChangesW.
                                                                                  Цитата Qraizer @
                                                                                  что вне ядра подсистемы синхронизации, типа как в винды, невозможно

                                                                                  Ключевые слова: "вне ядра невозможно". Можно написать кучу велосипедов, но пока нет доступа к ядерному планировщику потоков - это будет, имхо, только имитация. И да, в Линухах, *BSD-системах ядро открытое, там в принципе попытаться можно. Как? Я не в теме. Но думаю одним лишь загружаемым модулем не обойтись, как догадка.

                                                                                  shm, ты все правильно написал. Я так и реализовал, и других альтернатив не вижу. Хотя в моем случае - ожидание завершения потока, в принципе, можно зацепить на мьютекс. Но это ну совсем не критично в моем варианте. У меня это скорее дань к подходу к работе с внешними процессами, т.к. у меня выход из цикла - это по сути пару машиннх команд до завершения фонового потока.

                                                                                  Цитата shm @
                                                                                  Более сложное - использовать события ОС об изменения файла/каталога в асинхронном варианте.

                                                                                  Да, я бегло читал про возможности часто-используемых ОС-ей. В венде и линухах можно, во фряхе ... еще мутят (инфа от 2014 года), может уже и намутили.
                                                                                    Цитата Qraizer @
                                                                                    Я бы не был так категоричен.

                                                                                    То, что ты предлагаешь, в некоторых ЯП есть - это зеленые потоки. Но реализовать без языковой VM - это, по-сути, писать часть своей VM. Если бы комитет за это взялся - я бы просто офигел. Надеюсь С++ не скатится в недо си-шарпо-джавы.
                                                                                      Цитата JoeUser @
                                                                                      .. И в *nix подобного очень не хватает, всякие там libevent + inotify + fsnotify запиливают,

                                                                                      Имеется select, poll,epoll.
                                                                                      Выбирай по вкусу.
                                                                                        Цитата ЫукпШ @
                                                                                        Имеется select, poll,epoll.

                                                                                        Не "локальные" решения, а указанные мною либы претендуют на кроссплатформенные. К примеру:

                                                                                        Цитата
                                                                                        Currently, libevent supports /dev/poll, kqueue(2), event ports, POSIX select(2), Windows select(), poll(2), and epoll(4). The internal event mechanism is completely independent of the exposed event API, and a simple update of libevent can provide new functionality without having to redesign the applications. As a result, Libevent allows for portable application development and provides the most scalable event notification mechanism available on an operating system. Libevent can also be used for multi-threaded applications, either by isolating each event_base so that only a single thread accesses it, or by locked access to a single shared event_base. Libevent should compile on Linux, *BSD, Mac OS X, Solaris, Windows, and more.
                                                                                          Цитата JoeUser @
                                                                                          но пока нет доступа к ядерному планировщику потоков - это будет, имхо, только имитация

                                                                                          Дело не сколько в доступе к планировщику, а в обработке аппаратных прерываний.

                                                                                          Добавлено
                                                                                          Цитата JoeUser @
                                                                                          Хотя в моем случае - ожидание завершения потока, в принципе, можно зацепить на мьютекс.

                                                                                          И что тебе это даст?
                                                                                          Сообщение отредактировано: shm -
                                                                                            Цитата shm @
                                                                                            И что тебе это даст?

                                                                                            Временное примирение с Килей! :lol:

                                                                                            Добавлено
                                                                                            Цитата shm @
                                                                                            Дело не сколько в доступе к планировщику, а в обработке аппаратных прерываний.

                                                                                            А я не согласен!
                                                                                            Ну "захватил ты ресурс" (начал обрабатывать прерываание) , а если системный планировщик потоков вдруг задумает тебя задинамить на 10 сек? Владелец ты, или нет ... будешь висеть 10 сек на ожидании.
                                                                                              Цитата JoeUser @
                                                                                              Ну "захватил ты ресурс" (начал обрабатывать прерываание) , а если системный планировщик потоков вдруг задумает тебя задинамить на 10 сек? Владелец ты, или нет ... будешь висеть 10 сек на ожидании

                                                                                              Каким образом он это сделает, если обработчик еще не отослал EOI? :popcorn:

                                                                                              Добавлено
                                                                                              Если мысль не понятна, то поясню. Текущий поток, который исполняется на ядре может переключиться только 2 сценариями:
                                                                                              1. поток добровольно отдает управление: по сути это все блокирующие функции.
                                                                                              2. происходит аппаратное прерывание и ОС принудительно делает переключение.
                                                                                              Сообщение отредактировано: shm -
                                                                                                shm, на все вопросы отвечать не буду, хлопотно это цитировать вики :)

                                                                                                Но замечу ... давай определимся о какой "многозадачности мы говорим? из
                                                                                                общеупотребимых - "кооперативная" и "вытесняющая". В первом случае (а это
                                                                                                ранние версии Венды - поток сам решает, что и когда ему "отдавать". Во
                                                                                                втором - ядро решает:

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

                                                                                                Цитата shm @
                                                                                                поток добровольно отдает управление

                                                                                                ??? Это где и когда поток управлял своим выполнением ??? А системный планировщик потоков был всегда "свадебным генералом"???

                                                                                                Резюме

                                                                                                Кто-то из нас не имеет должных знаний, или не имеет тупо чуйки.
                                                                                                Допускаю, что я. А ты?
                                                                                                  JoeUser, на венде всё просто: любой пользовательский код работает на уровне приоритета ниже, чем у ... э-эм, "синхропроцесса", что и позволяет последнему указывать шедулеру, какой из потоков должен спать на объекте, а кто работать; синхропроцесс работает на максимальном "программном" уровне приоритета; все прерывания работают на уровнях выше "программного". Очень грубо, но даёт представление о взаимодействии приоритетов, объектов синхронизации и шедулера. Важный вывод: объекты синхронизации не могут использоваться обработчиками прерываний, т.к. у них приоритеты выше, чем те, которыми способен управлять "синхропроцесс". Так что как ни старайся, в лучшем случае WaitForXXXX() просто вернёт управление назад безусловно и безотносительно.
                                                                                                    Цитата Qraizer @
                                                                                                    oeUser, на венде всё просто: любой пользовательский код работает на уровне приоритета ниже, чем у ... э-эм, "синхропроцесса"

                                                                                                    Вангую, даже нет!!! Вещяю аки Соловьёв на TV - не только в венде, везде так. Иначе был бы аут и песец.

                                                                                                    Цитата Qraizer @
                                                                                                    все прерывания работают на уровнях выше "программного"

                                                                                                    Не в курсе, не знаю, но я бы вынес этот обработчик в kernel-space. А уж из него в usеr-program слал результаты (а лучше - ивенты).

                                                                                                    Цитата Qraizer @
                                                                                                    Важный вывод: объекты синхронизации не могут использоваться обработчиками прерываний

                                                                                                    Я-я ... гер майор - вся "аппаратура должна оседать в кернель моде". Это - справедливо!
                                                                                                      Цитата JoeUser @
                                                                                                      Цитата shm @
                                                                                                      И что тебе это даст?

                                                                                                      Временное примирение с Килей! :lol:

                                                                                                      Знаешь, чтобы решать такие задачи, надо приобретать
                                                                                                      базовые знания. На лекциях в ВУЗ-е, читая книги,
                                                                                                      разыскивая статьи и доки - самостоятельно.
                                                                                                      ---
                                                                                                      Конференция - это как курилка. Где можно услышать
                                                                                                      интересную мысль, узнать перспективный программный приём.
                                                                                                      А можно и не услышать и не узнать.
                                                                                                      Образования так не получишь.
                                                                                                      ---
                                                                                                      Книга - друг инженера.
                                                                                                        Цитата JoeUser @
                                                                                                        из
                                                                                                        общеупотребимых - "кооперативная" и "вытесняющая". В первом случае (а это
                                                                                                        ранние версии Венды - поток сам решает, что и когда ему "отдавать". Во
                                                                                                        втором - ядро решает:

                                                                                                        Почти во всех современных ОС многозадачность гибридная, т.е. обычно потоки отдают управление самостоятельно, но ОС может забрать управление по таймеру, если поток превысил допустимый квант времени.
                                                                                                        Цитата JoeUser @
                                                                                                        ??? Это где и когда поток управлял своим выполнением ???

                                                                                                        Любые блокирующие функции к этому приводят. Доказать могу легко: делаешь Sleep(N) - в это время загрузка потока будет 0, аналогично чтение файла и пр... Поток может добровольно отдать управление, гарантированно получить управление он не может.
                                                                                                        Цитата JoeUser @
                                                                                                        А системный планировщик потоков был всегда "свадебным генералом"???

                                                                                                        Я не понимаю о чем ты.
                                                                                                        Цитата JoeUser @
                                                                                                        Кто-то из нас не имеет должных знаний, или не имеет тупо чуйки.
                                                                                                        Допускаю, что я. А ты?

                                                                                                        У меня есть свое игрушечное мини-ядро ОС с поддержкой SMP. Это так, для общей информации. Об ядрах *nix и Win тоже знаю представление и рекомендую посмотреть исходники ReactOS.

                                                                                                        Добавлено
                                                                                                        Цитата JoeUser @
                                                                                                        Не в курсе, не знаю, но я бы вынес этот обработчик в kernel-space. А уж из него в usеr-program слал результаты (а лучше - ивенты).

                                                                                                        kernel-space != уровень приоритета
                                                                                                        Цитата JoeUser @
                                                                                                        Я-я ... гер майор - вся "аппаратура должна оседать в кернель моде". Это - справедливо!

                                                                                                        Разработчики микроядерных ОС с тобой несогласны.
                                                                                                        Сообщение отредактировано: shm -
                                                                                                          Цитата shm @
                                                                                                          Разработчики микроядерных ОС с тобой несогласны.

                                                                                                          Просто они хотрованы! Когда нормальные пацанчики разделяют "kernel-mode" и "usеr-mode", то они лепят еще один слой, и получается "kernel-mode"
                                                                                                          , "service-mode" и "usеr-mode". И в "service-mode" типа работает весь фарш. Ну давайте не будем кривить душой - откусили часть функционала ядра, обособили, снабдили большим чем юзер-спейс и меньшим чем кернель-спейс (возможно планировщик ядра повесили сверху). Ну да, может стало отзывчивее ... НО ОТ ЭТОГО АППАРАТУРА НА СТОРОНЕ ЮЗЕРА НЕ СТАЛА ОБРАБАТЫВАТЬСЯ! В загружаемых модулях, в "забытых детях ядра" :lol:
                                                                                                            Цитата JoeUser @
                                                                                                            Когда нормальные пацанчики разделяют "kernel-mode" и "usеr-mode", то они лепят еще один слой, и получается "kernel-mode"
                                                                                                            , "service-mode" и "usеr-mode".

                                                                                                            Бывают и всего с 2 слоями.
                                                                                                            Цитата JoeUser @
                                                                                                            Ну давайте не будем кривить душой - откусили часть функционала ядра, обособили, снабдили большим чем юзер-спейс и меньшим чем кернель-спейс (возможно планировщик ядра повесили сверху). Ну да, может стало отзывчивее ... НО ОТ ЭТОГО АППАРАТУРА НА СТОРОНЕ ЮЗЕРА НЕ СТАЛА ОБРАБАТЫВАТЬСЯ! В загружаемых модулях, в "забытых детях ядра"

                                                                                                            Микроядерные ОС не отзывчивее монолитных. Там фишка в другом - они (в теории) стабильнее и безопаснее. И да, в некоторый микроядерных ОС прерывания обрабатываются в user-space.
                                                                                                              Цитата JoeUser @
                                                                                                              НО ОТ ЭТОГО АППАРАТУРА НА СТОРОНЕ ЮЗЕРА НЕ СТАЛА ОБРАБАТЫВАТЬСЯ!

                                                                                                              Давно уже можно на стороне юзера обрабатывать теже сетевые пакеты минуя стек ОС полностью ;)
                                                                                                                Цитата Gonarh @
                                                                                                                Давно уже можно на стороне юзера обрабатывать теже сетевые пакеты минуя стек ОС полностью

                                                                                                                Но это вот не значит же, что это программа напрямую общается с аппаратурой сетевого контроллера? Если речь идет о сырых сокетах, так то через API операционных систем.
                                                                                                                  Цитата JoeUser @
                                                                                                                  Но это вот не значит же, что это программа напрямую общается с аппаратурой сетевого контроллера?

                                                                                                                  Ну драйвер конечно нужен, НО, только для инициализации железки и предоставление интерфейса. Затем делается анбинд сетевухи, чтобы ОСь не дёргалась на неё вообще. Я попробовал туда сунуться, хотел по минимуму сетевой стек нарисовать, хотя бы базовое типа arp/ip, обычная маршрутизация трафика, но не хватает мозгов, лазию читаю, облизываюсь.
                                                                                                                  Сообщение отредактировано: Gonarh -
                                                                                                                    Цитата Gonarh @
                                                                                                                    Ну драйвер конечно нужен,

                                                                                                                    Вот поэтому и говорим, что драйвер дает только API для управления "железом". Хотя, я как-то встречал интересный драйвер уровня ядра для винды, что-то типа portio.sys (не помню точно). Цель создания этой дровины - дать доступ из режима пользователя к портам железа. Да, и драйвер был, и проги были, его использующие. Но это все равно "хак", а не нормальное программирование. Зачем создавать и отлаживать защищенные механизмы Оси, если вот такие дыры в ней проделывают?
                                                                                                                      Цитата JoeUser @
                                                                                                                      Зачем создавать и отлаживать защищенные механизмы Оси, если вот такие дыры в ней проделывают?

                                                                                                                      Затем, что если убрать обработку сетевого пакета тем же линухом, и обработать его самому, то время обработки сократиться до ~60 циклов CPU на пакет, вот и посчитай какие хайлоад системы по обработке сетевого трафика можно реализовать, сиськи с джуниперами нервно курят в сторонке.
                                                                                                                      Сообщение отредактировано: Gonarh -
                                                                                                                        Цитата Gonarh @
                                                                                                                        Затем, что если убрать обработку сетевого пакета тем же линухом, и обработать его самому, то время обработки сократиться до ~60 циклов CPU на пакет, вот и посчитай какие хайлоад системы по обработке сетевого трафика можно реализовать, сиськи с джуниперами нервно курят в сторонке.

                                                                                                                        И все равно я не согласен. Не хочешь отдавать пакеты родному стеку - напиши свой загружаемый модуль и в нем обрабатывай. С точки зрения защищенности системы - это, правильнее ИМХО.

                                                                                                                        ЗЫ: Хотя мы, походу, уходим куда-то в сторону от темы топика :-?
                                                                                                                        0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                                                                                                        0 пользователей:


                                                                                                                        Рейтинг@Mail.ru
                                                                                                                        [ Script execution time: 0,1730 ]   [ 17 queries used ]   [ Generated: 16.04.24, 07:58 GMT ]