Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.224.32.86] |
|
Сообщ.
#1
,
|
|
|
Нужно сделать такую программу. Консольная программа в бесконечном цикле ожидает ввода текстовых команд. Сначала вводим начальные данные, в том числе максимальное время вычислений. Зачем ждем следующих команд. При вводе команды старт нужно запустить вычисления в параллельном потоке и перейти в режим ожидания следующей команды. В процессе вычисления результат постепенно уточняется в зависимости от достигнутой глубины исследования. При истечении определенного времени по таймеру или при вводе команды стоп нужно немедленно остановить вычисления и выдать результат в консоль.
Как это можно реализовать? Пока смог сделал только с помощью WinAPI и без таймера. #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(). Причем так, чтоб основной поток не зависал. |
Сообщ.
#2
,
|
|
|
S.Eugene, самый простой вариант -- периодически дергать WaitForSingleObject(h, 0) в рабочем потоке.
|
Сообщ.
#3
,
|
|
|
Цитата S.Eugene @ Как можно инициировать таймер и вызывать с его помощью StopCalc(). Причем так, чтоб основной поток не зависал. Таймер можно создать посредством "CreateWaitableTimer". Посмотри MSDN, есть и другие ф-ии работы с таймером. пример |
Сообщ.
#4
,
|
|
|
Цитата S.Eugene @ Нужно сделать такую программу. Консольная программа в бесконечном цикле ожидает ввода текстовых команд. При вводе команды старт нужно запустить вычисления в параллельном потоке и перейти в режим ожидания следующей команды. Неправильная архитектура детектед!!! И все это ... богомергзое WinAPI Каюсь, грешен, до сей поры помню, что "поток можно остановить" и "поток можно убить". Но это не С++way. Нет там такого! "Ломка" будет, к гадалке не ходи. Отвлеченно. Скрытый текст Поток - это лесоруб. У него есть задание - рубить лес. С++ way: "эй, прекращай рубить!", "окей, последний удар, лесоруб ждет" WinAPI-way: "лесоруб, прицел, выстрел" Итого: * запускаем два потока, один ждет ввода, второй команд * второй умеет считать, умеет "зависать" по условию, умеет прекращать вычисления Все решается с помощью std::atomic, std::condition_variable, пробросом исключений в n-вложенных циклах для рестарта/стопа Вот как-то так |
Сообщ.
#5
,
|
|
|
Поставил таймер в отельный поток. Вроде все работает. Только я не могу сообразить, будет ли всегда работать, не будет ли фоновых потоков сирот? Варианта окончания вычислений три: вычисления заканчиваются сами по себе, вычисления заканчиваются командой стоп, вычисления заканчиваются по таймеру. Не уверен, что если, например, таймер и команда стоп одновременно сработают, то все корректно закончится.
#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; } |
Сообщ.
#6
,
|
|
|
S.Eugene, первый поток должен управлять вторым.
* Запустить * Пользовать его * Остановить (и второй поток должен сообщить типа "жду команд") * Завершить второй поток * Завершить себя Вопросы? |
Сообщ.
#7
,
|
|
|
Цитата JoeUser @ S.Eugene, первый поток должен управлять вторым. * Запустить * Пользовать его * Остановить (и второй поток должен сообщить типа "жду команд") * Завершить второй поток * Завершить себя Вопросы? Как запустить, как остановить, как завершить? Где об этом понятно и последовательно написано? Вообще, я только вчера взялся изучать потоки. Никогда с ними не сталкивался. Узнал про ptheard по примерам, немного посмотрел по книгам и даже видео лекции нашел. Теоретически вроде все понял. Попробовал писать свой первый пример, а в студии нет ptheard.h. Потом попробовал подключить аналог boost::thread, но ее тоже нет в студии. Тогда пришлось обращаться к WinAPI. Вообще, изначально хотел что-то более простое и кроссплатформенное. Был удивлен, что в студии нет средств для потоков. Если не ошибаюсь, в двухтысячных годах в Делфи7 уже был удобный и простой класс TThread для потоков. |
Сообщ.
#8
,
|
|
|
Цитата S.Eugene @ Как запустить, как остановить, как завершить? Где об этом понятно и последовательно написано? Лови тут. Ток учти, я сей документ, точнее его оглавление - примерно час форматил, пальцы практически в кровь до костей. Если ты верующий, ты просто обязан сделать в мою честь что-то богоугодное. Свечку в церьковь, намаз, ну или на праздник Дивали сплясать ... морское "яблочко" |
Сообщ.
#9
,
|
|
|
S.Eugene, если winapi тебе не принципиально, то используй http://ru.cppreference.com/w/cpp/thread/thread. Для поддержки нужен новый компилятор.
|
Сообщ.
#10
,
|
|
|
Цитата shm @ S.Eugene, если winapi тебе не принципиально, то используй http://ru.cppreference.com/w/cpp/thread/thread. Для поддержки нужен новый компилятор. Уже смотрел. Только я не понял, есть ли там аналоги pthread_cancel и pthread_testcancel, pthread_exit и т.п. Студия у меня новая, 15я. Неделю назад установил. |
Сообщ.
#11
,
|
|
|
Цитата S.Eugene @ есть ли там аналоги pthread_cancel и pthread_testcancel, pthread_exit и т.п Зачем тебе они? |
Сообщ.
#12
,
|
|
|
Цитата shm @ Зачем тебе они? Потому что с pthread есть примеры. |
Сообщ.
#13
,
|
|
|
Что-то я пока даже теоретически не могу придумать, как все сделать.
Идея такая. Всего будет три потока. Поток0 - главный, который всегда читает команды из ввода. Когда получаем команду старт, инициируем начальные параметры и запускаем Поток1. Поток1 запускает Поток2 для вычислений, затем инициирует таймер, останавливается и начинает ждать срабатывание таймера. После срабатывания таймера Поток1 просыпается, уничтожает Поток2, где шли вычисления, а затем выводит результат. Затем уничтожается сам. Можно как-то сделать так, чтоб Поток1 просыпался не только от сигнала таймера, но и от сигнала стоп из Потока0, и сигнала об окончании вычислений из Потока2. |
Сообщ.
#14
,
|
|
|
WaitForMultipleObjects
|