На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Обратите внимание:
1. Прежде чем начать новую тему или отправить сообщение, убедитесь, что вы не нарушаете правил форума!
2. Обязательно воспользуйтесь поиском. Возможно, Ваш вопрос уже обсуждали. Полезные ссылки приведены ниже.
3. Темы с просьбой выполнить какую-либо работу за автора в этом разделе не обсуждаются.
4. Используйте теги [ code=cpp ] ...текст программы... [ /code ] для выделения текста программы подсветкой.
5. Помните, здесь телепатов нет. Старайтесь формулировать свой вопрос максимально грамотно и чётко: Как правильно задавать вопросы
6. Запрещено отвечать в темы месячной и более давности без веских на то причин.

Полезные ссылки:
user posted image FAQ Сайта (C++) user posted image FAQ Форума user posted image Наши Исходники user posted image Поиск по Разделу user posted image MSDN Library Online (Windows Driver Kit) user posted image Google

Ваше мнение о модераторах: user posted image B.V.
Модераторы: B.V.
  
> Как запустить поток, а затем остановить его командой или по таймеру? , Как сделать свою командную оболочку?
    Нужно сделать такую программу. Консольная программа в бесконечном цикле ожидает ввода текстовых команд. Сначала вводим начальные данные, в том числе максимальное время вычислений. Зачем ждем следующих команд. При вводе команды старт нужно запустить вычисления в параллельном потоке и перейти в режим ожидания следующей команды. В процессе вычисления результат постепенно уточняется в зависимости от достигнутой глубины исследования. При истечении определенного времени по таймеру или при вводе команды стоп нужно немедленно остановить вычисления и выдать результат в консоль.

    Как это можно реализовать?

    Пока смог сделал только с помощью WinAPI и без таймера.

    ExpandedWrap disabled
      #include "stdafx.h"
      #include <iostream>
      #include <string>
      #include <windows.h>
       
      using namespace std;
       
      HANDLE ht = NULL;
      string str;
       
      int x, n; // в эти переменные вводимые извне параметры для вычислений
      int Result; // сюда записываем результат вычислений
       
      void OutResult()
      {
        cout << "Result=" << Result << endl;
      }
       
      void StopCalc()
      {
        if ( ht != NULL ) // если вычисления идут
        {
          TerminateThread(ht, 0);
          ht = NULL;
        }
        OutResult();
      }
       
      DWORD WINAPI mycalc(LPVOID)
      {
        int r = 0;
        for ( int i = 0; i < n; i++ )
        {
          Sleep(4000); // какое-то долгое вычисление  
          r = r + x;  // очень сложное вычисление
       
          cout << "r=" << r << endl; //вывод информации о ходе вычислений
       
          Result = r; //запись промежуточного результата
        }
        return 0;
      }
       
      int main()
      {
        while ( true )
        {
          getline(cin, str);
          
          /*
            Тут распознаем команду ввода новых параметров из str и заносим значения
            x = ...;
            n = ...;
          */
       
          if ( str == "start" )
          {
            if ( ht == NULL ) //если не идут никакие вычисления
            {
              Result = 0; //обнуление результата перед новым вычислением
              x = 1, n = 100; //инициация новых значений параметров для вычислений
              ht = CreateThread(NULL, 0, mycalc, NULL, 0, NULL);
            }
            continue;
          }
       
          if ( str == "stop" )
          {    
            StopCalc();
            continue;
          }
       
          if ( str == "quit" ) break;
        }
       
        return 0;
      }


    При поступлении команды start проверяем запускали ли мы процесс. Для этого просто проверяем, равен ли NULL указатель на поток.

    Если нет, то инициируются переменные-параметры для вычисления, обнуляются общие переменные для запоминания результата, запускается второй поток.

    Если поток вычислений уже запущен, то игнорируем, чтоб не было два дочерних потока.

    Команда stop убивает поток, присваивает NULL указателю на поток, и выводит результат, который сохранился в общей памяти.

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


    Как можно инициировать таймер и вызывать с его помощью StopCalc(). Причем так, чтоб основной поток не зависал.
    Сообщение отредактировано: S.Eugene -
      S.Eugene, самый простой вариант -- периодически дергать WaitForSingleObject(h, 0) в рабочем потоке.
      Сообщение отредактировано: shm -
        Цитата S.Eugene @
        Как можно инициировать таймер и вызывать с его помощью StopCalc(). Причем так, чтоб основной поток не зависал.

        Таймер можно создать посредством "CreateWaitableTimer".
        Посмотри MSDN, есть и другие ф-ии работы с таймером.
        пример
        Сообщение отредактировано: ЫукпШ -
          Цитата S.Eugene @
          Нужно сделать такую программу. Консольная программа в бесконечном цикле ожидает ввода текстовых команд. При вводе команды старт нужно запустить вычисления в параллельном потоке и перейти в режим ожидания следующей команды.

          Неправильная архитектура детектед!!! :wall:

          И все это ... богомергзое WinAPI :lol: Каюсь, грешен, до сей поры помню, что "поток можно остановить" и "поток можно убить". Но это не С++way. Нет там такого! "Ломка" будет, к гадалке не ходи.

          Отвлеченно.
          Скрытый текст
          Поток - это лесоруб. У него есть задание - рубить лес.
          С++ way: "эй, прекращай рубить!", "окей, последний удар, лесоруб ждет"
          WinAPI-way: "лесоруб, прицел, выстрел"

          Итого:

          * запускаем два потока, один ждет ввода, второй команд
          * второй умеет считать, умеет "зависать" по условию, умеет прекращать вычисления

          Все решается с помощью std::atomic, std::condition_variable, пробросом исключений в n-вложенных циклах для рестарта/стопа
          Вот как-то так :-?
            Поставил таймер в отельный поток. Вроде все работает. Только я не могу сообразить, будет ли всегда работать, не будет ли фоновых потоков сирот? Варианта окончания вычислений три: вычисления заканчиваются сами по себе, вычисления заканчиваются командой стоп, вычисления заканчиваются по таймеру. Не уверен, что если, например, таймер и команда стоп одновременно сработают, то все корректно закончится. :-?

            ExpandedWrap disabled
              #include "stdafx.h"
              #include <iostream>
              #include <string>
              #include <windows.h>
               
              using namespace std;
               
              HANDLE ht = NULL, ht2 = NULL;
              string str;
               
              int x, n; // в эти переменные вводимые извне параметры для вычислений
              UINT maxtime; //максимальное время вычислений
              int Result; // результат
               
              void OutResult()
              {
                cout << "Result=" << Result << endl;
              }
               
              void CALLBACK StopCalc()
              {
                if ( ht != NULL ) // если вычисления идут
                {
                  TerminateThread(ht, 0);
                  ht = NULL;
                }
                OutResult();
                TerminateThread(ht2, 0);
              }
               
              DWORD WINAPI mycalc(LPVOID)
              {
                int r = 0;
                for ( int i = 0; i < n; i++ )
                {
                  Sleep(4000); // какое-то долгое вычисление  
                  r = r + x; // очень сложное вычисление
                  
                  cout << "r=" << r << endl; //вывод информации о ходе вычислений
               
                  Result = r; //запись промежуточного результата
                }
                PrintResult();
                TerminateThread(ht2, 0);
                return 0;
              }
               
              DWORD WINAPI timerinit(LPVOID)
              {
                UINT htimer = SetTimer(NULL, NULL, maxtime, (TIMERPROC)StopCalc);
                MSG msg;
                while ( GetMessage(&msg, 0, 0, 0) ) DispatchMessage(&msg);
                KillTimer(NULL, htimer);
                return 0;
              }
               
              int main()
              {
                while ( true )
                {
                  getline(cin, str);
               
                  if ( str == "start" )
                  {
                    if ( ht == NULL ) //если не идут никакие вычисления
                    {
                      Result = 0; //обнуление результата перед новым вычислением
               
                      x = 1, n = 100; //инициация новых значений параметров для вычислений
                      ht = CreateThread(NULL, 0, mycalc, NULL, 0, NULL);
               
                      maxtime = 10000; //запускаем поток, в котором запустим таймер, который убьет поток ht и себя.
                      ht2 = CreateThread(NULL, 0, timerinit, NULL, 0, NULL);
                    }
                    continue;
                  }
               
                  if ( str == "stop" )
                  {    
                    StopCalc();
                    continue;
                  }
               
                  if ( str == "quit" ) break;
                }
               
                return 0;
              }
            Сообщение отредактировано: S.Eugene -
              S.Eugene, первый поток должен управлять вторым.

              * Запустить
              * Пользовать его
              * Остановить (и второй поток должен сообщить типа "жду команд")
              * Завершить второй поток
              * Завершить себя

              Вопросы?
                Цитата JoeUser @
                S.Eugene, первый поток должен управлять вторым.

                * Запустить
                * Пользовать его
                * Остановить (и второй поток должен сообщить типа "жду команд")
                * Завершить второй поток
                * Завершить себя

                Вопросы?

                Как запустить, как остановить, как завершить? Где об этом понятно и последовательно написано?

                Вообще, я только вчера взялся изучать потоки. Никогда с ними не сталкивался. Узнал про ptheard по примерам, немного посмотрел по книгам и даже видео лекции нашел. Теоретически вроде все понял. Попробовал писать свой первый пример, а в студии нет ptheard.h. Потом попробовал подключить аналог boost::thread, но ее тоже нет в студии. Тогда пришлось обращаться к WinAPI. Вообще, изначально хотел что-то более простое и кроссплатформенное. Был удивлен, что в студии нет средств для потоков. Если не ошибаюсь, в двухтысячных годах в Делфи7 уже был удобный и простой класс TThread для потоков.
                Сообщение отредактировано: S.Eugene -
                  Цитата S.Eugene @
                  Как запустить, как остановить, как завершить? Где об этом понятно и последовательно написано?

                  Лови тут. Ток учти, я сей документ, точнее его оглавление - примерно час форматил, пальцы практически в кровь до костей. Если ты верующий, ты просто обязан сделать в мою честь что-то богоугодное. Свечку в церьковь, намаз, ну или на праздник Дивали сплясать ... морское "яблочко" :lol:
                    S.Eugene, если winapi тебе не принципиально, то используй http://ru.cppreference.com/w/cpp/thread/thread. Для поддержки нужен новый компилятор.
                      Цитата shm @
                      S.Eugene, если winapi тебе не принципиально, то используй http://ru.cppreference.com/w/cpp/thread/thread. Для поддержки нужен новый компилятор.

                      Уже смотрел. Только я не понял, есть ли там аналоги pthread_cancel и pthread_testcancel, pthread_exit и т.п. Студия у меня новая, 15я. Неделю назад установил.
                        Цитата S.Eugene @
                        есть ли там аналоги pthread_cancel и pthread_testcancel, pthread_exit и т.п

                        Зачем тебе они?
                          Цитата shm @
                          Зачем тебе они?

                          Потому что с pthread есть примеры.
                            Что-то я пока даже теоретически не могу придумать, как все сделать.

                            Идея такая.

                            Всего будет три потока.

                            Поток0 - главный, который всегда читает команды из ввода.

                            Когда получаем команду старт, инициируем начальные параметры и запускаем Поток1.

                            Поток1 запускает Поток2 для вычислений, затем инициирует таймер, останавливается и начинает ждать срабатывание таймера. После срабатывания таймера Поток1 просыпается, уничтожает Поток2, где шли вычисления, а затем выводит результат. Затем уничтожается сам.

                            Можно как-то сделать так, чтоб Поток1 просыпался не только от сигнала таймера, но и от сигнала стоп из Потока0, и сигнала об окончании вычислений из Потока2.
                              WaitForMultipleObjects
                              Сообщение отредактировано: MBo -
                              0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                              0 пользователей:


                              Рейтинг@Mail.ru
                              [ Script execution time: 0,3094 ]   [ 17 queries used ]   [ Generated: 25.04.24, 11:42 GMT ]