2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки





Начать новую тему Ответить на тему
 
 Как запустить параллельный поток и остановить по таймеру?
Сообщение19.12.2016, 02:46 


25/11/08
399
Нужно сделать такую программу. Консольная программа в бесконечном цикле ожидает ввода текстовых команд. Сначала вводим начальные данные, в том числе максимальное время вычислений. Зачем ждем ввода следующей команды. При вводе команды старт нужно запустить вычисления в параллельном потоке и сразу перейти в режим ожидания следующей команды. В процессе вычисления результат постепенно уточняется в зависимости от достигнутой глубины исследования. При истечении определенного времени по таймеру или при вводе команды стоп нужно немедленно остановить вычисления и вывести результат в консоль. Затем все повторяется. Как это лучше организовать?

Пока есть только такая идея.

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

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

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

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

Можно как-то сделать так, чтоб Поток1 просыпался не только от сигнала таймера, но и от сигнала стоп из Потока0, и сигнала об окончании вычислений из Потока2?

Какими средствами C++ это можно сделать? Желательно кроссплатформенными, без WinAPI.

 Профиль  
                  
 
 Re: Как запустить параллельный поток и остановить по таймеру?
Сообщение19.12.2016, 08:11 


11/12/14
865
Кроссплатформенный - это библиотека pthreads, в том же MinGW присутствует из коробки, или std::thread из C++11, который во многом обёртка из классов над pthreads, так что не сильно суть.
Естественно сперва следует почитать учебник по ней и многопоточному программированию, все эти синхронизирующие примитивы, и т.п., в двух словах не расскажешь.
Собственно после прочтения всё будет и понятно сразу же.
Такое обычно делается так - Поток0 запускает Поток1, выставив нужные синхронизирующие примитивы. Работа Потока1 организована таким образом, что он несколько раз в секунду "отвлекается" от основной работы и проверяет не выставил ли Поток0 ему приказ остановится досрочно, а завершаясь выставляет Потоку0 информацию о том, что завершился и положил результаты куда надо. Поток0, соответственно, выставляет и реагирует.
Очень нехорошо размышлять в терминах "уничтожает" или "досрочно прибивает", потоки должны завершаться добровольно, по своей воле, полностью контролируя происходящее вокруг и в штатном режиме вызывая деструкторы своих объектов.

 Профиль  
                  
 
 Re: Как запустить параллельный поток и остановить по таймеру?
Сообщение19.12.2016, 13:54 


25/11/08
399
aa_dav в сообщении #1178273 писал(а):
Кроссплатформенный - это библиотека pthreads, в том же MinGW присутствует из коробки, или std::thread из C++11, который во многом обёртка из классов над pthreads, так что не сильно суть.
Честно говоря, кроссплатформенность не особо нужна, просто не хочется возиться с низкоуровневым winapi. Пока мне удобнее всего использовать встроенный в студию 15 <thread>. Вот только я не нахожу там всех аналогов pthread. Например, pthread_cancel и pthread_testcancel.

aa_dav в сообщении #1178273 писал(а):
Естественно сперва следует почитать учебник по ней и многопоточному программированию, все эти синхронизирующие примитивы, и т.п., в двух словах не расскажешь.
Уже читал и про мьютексы, и про условные переменные. Все равно затрудняюсь сообразить, как все устроить.

Цитата:
Поток0 запускает Поток1, выставив нужные синхронизирующие примитивы. Работа Потока1 организована таким образом, что он несколько раз в секунду "отвлекается" от основной работы и проверяет не выставил ли Поток0 ему приказ остановится досрочно
Наверное, нужно в общей памяти поставить флаг, который Поток1 будем периодически проверять, захватывая мьютекс? На частые обращения не расходуется много ресурсов?

Цитата:
а завершаясь выставляет Потоку0 информацию о том, что завершился и положил результаты куда надо.
Поток0 во время работы Потока1 ждет ввода текстовых команд на cin. Как он может на что-то реагировать?

 Профиль  
                  
 
 Re: Как запустить параллельный поток и остановить по таймеру?
Сообщение19.12.2016, 19:28 
Заслуженный участник
Аватара пользователя


27/04/09
21259
Уфа
Я так понимаю, это делает не Поток0, а Поток2, запущеный тоже из нулевого.

 Профиль  
                  
 
 Re: Как запустить параллельный поток и остановить по таймеру?
Сообщение19.12.2016, 22:23 
Аватара пользователя


31/10/08
805
ellipse
ellipse в сообщении #1178320 писал(а):
Наверное, нужно в общей памяти поставить флаг, который Поток1 будем периодически проверять, захватывая мьютекс?

Верно.
ellipse в сообщении #1178320 писал(а):
На частые обращения не расходуется много ресурсов?

Это сложный вопрос, в том смысле что как правило все новички ошибаются или делают поспешные выводы. Причем как в одну сторону так и в другую.
Если там есть паузы, то расходуется мало.
ellipse в сообщении #1178320 писал(а):
Поток0 во время работы Потока1 ждет ввода текстовых команд на cin. Как он может на что-то реагировать?

aa_dav не учёл особенности консольных приложений. Да может. Но давайте считать что нет, так как у консольного приложения нет очереди сообщений. Соответственно две задачи ждать таймер и ждать ввод не могут быть обработаны независимо в одном потоке. Соответственно пока не закончится ввод таймаут не сработает.
В разных потоках обработать можно.

ellipse в сообщении #1178320 писал(а):
Вот только я не нахожу там всех аналогов pthread. Например, pthread_cancel и pthread_testcancel.

http://en.cppreference.com/w/c/thread

cnd_wait - blocks on a condition variable
cnd_timedwait - blocks on a condition variable, with a timeout

 Профиль  
                  
 
 Re: Как запустить параллельный поток и остановить по таймеру?
Сообщение19.12.2016, 22:58 


20/08/14
3458
Россия, Москва
А зачем непременно нужен Поток1, почему нельзя в переменную положить время окончания работы Потока2 и в нём самом несколько раз в секунду проверять не превысили ли это время и если да, то корректно останавливаться и закрываться? Всё равно же в нём проверять флаг требования останова, можно их легко совместить в одно проверяемое условие. И сигнал останова из Потока0 в Поток2 посылать как обнуление этого запомненного времени останова - Поток2 быстро и корректно сам по нему остановится.

 Профиль  
                  
 
 Re: Как запустить параллельный поток и остановить по таймеру?
Сообщение20.12.2016, 09:51 
Заслуженный участник
Аватара пользователя


02/08/11
4441
aa_dav в сообщении #1178273 писал(а):
Работа Потока1 организована таким образом, что он несколько раз в секунду "отвлекается" от основной работы и проверяет не выставил ли Поток0 ему приказ остановится досрочно
Поскольку Поток 1 по условию не делает никакой работы, а ждёт срабатывания таймера, то надо просто ждать либо срабатывания таймера, либо нотификации (что само по себе уже сложная задача, см. ниже) из Потока 0.

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

 Профиль  
                  
 
 Re: Как запустить параллельный поток и остановить по таймеру?
Сообщение20.12.2016, 11:06 


11/12/14
865
warlock66613 в сообщении #1178540 писал(а):
Поскольку Поток 1 по условию не делает никакой работы, а ждёт срабатывания таймера


Не в предложенной мной схеме. В моей схеме основной работой, включая вычисления и проверку на таймер делает Поток1. Забыл это подчеркнуть. Его рабочие циклы просто сконструированы так, чтобы не менее, чем, к примеру, 10 раз в секунду проверять не прошло ли достаточно времени или не появилось ли флагов завершения от Потока0.
Кстати насчёт консоли - да, она не очень хорошо в это ложится, т.к. ввод/вывод от двух потоков могут пересекаться, что неаккуратно как минимум. Хотя, если для личных нужд, а не коммерции, с этим вполне можно жить.
Я бы сделал по другому - Поток0 выводит подобие меню:
(A)bort e(X)it (S)how ... и так далее
и в цикле спит 100 мс, а после проверяет нет ли результатов от Потока0 либо нет ли в буфере клавиатуры введенных символов.
вполне себе интерактивно получится и без рисков пересечения выводов, потому что выводить будет только Поток0.

 Профиль  
                  
 
 Re: Как запустить параллельный поток и остановить по таймеру?
Сообщение23.12.2016, 03:14 
Аватара пользователя


07/02/12
1093
Питер
ellipse в сообщении #1178242 писал(а):
Желательно кроссплатформенными, без WinAPI

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

 Профиль  
                  
 
 Re: Как запустить параллельный поток и остановить по таймеру?
Сообщение23.12.2016, 21:09 
Заслуженный участник
Аватара пользователя


02/08/11
4441
bondkim137 в сообщении #1179353 писал(а):
например, для Win32 одну, для линукс-освместимых другую
В случае современного C++ обёртки уже написаны, остаётся только научиться ими пользоваться.

 Профиль  
                  
 
 Re: Как запустить параллельный поток и остановить по таймеру?
Сообщение24.12.2016, 03:08 
Аватара пользователя


07/02/12
1093
Питер
Для уровня лаборатных - да, а так остаются нюансы.
Чем глубже копать, тем больше последних всплывает и портит жизнь.

 Профиль  
                  
 
 Re: Как запустить параллельный поток и остановить по таймеру?
Сообщение01.01.2017, 11:05 


01/01/17
5
Pavia в сообщении #1178449 писал(а):
http://en.cppreference.com/w/c/thread

Диванного видно сразу.

Идём по ссылке
http://en.cppreference.com/w/c/thread писал(а):
If the macro constant __STDC_NO_THREADS__(C11) is defined by the compiler, the header <threads.h> and all of the names listed here are not provided.

Проверяем
gcc писал(а):
$ gcc -std=c11 -dM -E - < /dev/null | grep __STDC_NO_THREADS__
#define __STDC_NO_THREADS__ 1

Лол.

 Профиль  
                  
 
 Re: Как запустить параллельный поток и остановить по таймеру?
Сообщение01.01.2017, 19:35 
Аватара пользователя


31/10/08
805
Ну да gcc не является образцовым компилятором. Оттого ему весь стандарт поддерживать не надо.
Но если уж хочется можете скачать https://github.com/jtsiomb/c11threads

 Профиль  
                  
 
 Re: Как запустить параллельный поток и остановить по таймеру?
Сообщение03.01.2017, 20:51 


13/06/10
3
ellipse в сообщении #1178242 писал(а):
Можно как-то сделать так, чтоб Поток1 просыпался не только от сигнала таймера, но и от сигнала стоп из Потока0, и сигнала об окончании вычислений из Потока2?


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

Вам нужен manual reset event, который сам вычислительный поток проверяет и корректно завершается если флажок взведен.

 Профиль  
                  
 
 Re: Как запустить параллельный поток и остановить по таймеру?
Сообщение13.01.2017, 12:54 


01/01/17
5
Pavia в сообщении #1181304 писал(а):
Оттого ему весь стандарт поддерживать не надо.
Стандарт явно говорит, что можно: либо иметь thread.h, либо определить __STDC_NO_THREADS__. Второй вариант такая же полная поддержка стандарта, как и первый. Так что у gcc всё в этом плане в порядке.
Pavia в сообщении #1181304 писал(а):
Но если уж хочется можете скачать https://github.com/jtsiomb/c11threads
Зачем брать куцую обёртку над POSIX-тредами, когда можно взять сами POSIX-треды?

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 15 ] 

Модераторы: maxal, Karan, Toucan, PAV, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group