прерываение выполнения по таймеру
От: maks1180  
Дата: 12.01.22 16:54
Оценка:
В консольном приложение нужно прерывать выполнение кода регулярно, скажем 1 раз в секунду и вызывать свою функцию что-бы выводить статус.
Т.е. что-бы именно основной поток заходил в мою функцию, а не другой поток.
Можно ли указать участок коды выполнение которого нельзя прерывать ? Т.е. что-бы при заполнении струкруры данных, она либо полностью была заполнена либо ещё не тронута.

В линукс прерывание по таймеру можно реализовать через сигналы.
signal(SIGALRM, sighandler); // Устанавливаем обработчик прерывания
alarm(5); // Задаём интервал 5 секунд

Как это можно сделать в Windows или кроссплатформенно ?
===============================================
(реклама, удалена модератором)
Re: прерываение выполнения по таймеру
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 12.01.22 17:10
Оценка:
Здравствуйте, maks1180, Вы писали:

M>что-бы именно основной поток заходил в мою функцию, а не другой поток.

M>Можно ли указать участок коды выполнение которого нельзя прерывать ?

В WinAPI вообще нет средств, позволяющих пользовательскому коду произвольно прерывать выполнение пользовательского же потока. Такое применяется в однопоточных системах, где невозможно организовать естественный параллелизм. В WinAPI переключение потока на пользовательский код возможно лишь в alertable-состоянии, в которое поток может войти только явно (например, через SleepEx и подобные функции).

Произвольно прерывать поток может только ядерный код.
Отредактировано 12.01.2022 17:11 Евгений Музыченко . Предыдущая версия .
Re[2]: прерываение выполнения по таймеру
От: maks1180  
Дата: 12.01.22 18:26
Оценка:
ЕМ>Произвольно прерывать поток может только ядерный код.

Ну да, ядерный код, должен в определённое время прервать определённый поток и передать выполнение заранее определённой функции.
Осталось найти WinAPI функции, что-бы сообщить это ядру.
===============================================
(реклама, удалена модератором)
Re[3]: прерываение выполнения по таймеру
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 12.01.22 18:33
Оценка:
Здравствуйте, maks1180, Вы писали:

M>Осталось найти WinAPI функции, что-бы сообщить это ядру.


Я же сказал — ее не существует. И это очень хорошо.
Re[4]: прерываение выполнения по таймеру
От: maks1180  
Дата: 12.01.22 20:38
Оценка:
M>>Осталось найти WinAPI функции, что-бы сообщить это ядру.

ЕМ>Я же сказал — ее не существует. И это очень хорошо.


Почему хорошо ?
===============================================
(реклама, удалена модератором)
Re[5]: прерываение выполнения по таймеру
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 12.01.22 20:45
Оценка:
Здравствуйте, maks1180, Вы писали:

M>Почему хорошо ?


Потому, что поддержка прерываний еще и на уровне пользовательского кода — это дополнительный геморрой по хранению правил переходов, текущих состояний, предоставлению примитивов по управлению всем этим, а для чего? Повторю: эти техники используются от бедности отсутствия нормальной, человеческой многопоточности, которая позволяет коду автоматически масштабироваться между одним процессором и бесконечностью их.
Re[5]: прерываение выполнения по таймеру
От: ononim  
Дата: 12.01.22 20:58
Оценка: +2
ЕМ>>Я же сказал — ее не существует. И это очень хорошо.
M>Почему хорошо ?
Ну вот вы аппелируете к сигналам, а вы в курсе, что список функций libc, которыми может пользоваться обработчик сигнала крайне ограничен? Даже printf'ом нельзя пользоваться, не говоря уж о malloc'е. А если оно у вас работает, то это благодаря высокому уровню удачи. Реально самый адекватный способ работы с сигналами — это блокировать их все нахрен, и крутить sigwait или же signalfd + select/poll. То есть по сути — аналог alertable wait.
Как много веселых ребят, и все делают велосипед...
Отредактировано 12.01.2022 21:06 ononim . Предыдущая версия . Еще …
Отредактировано 12.01.2022 21:01 ononim . Предыдущая версия .
Re[2]: прерываение выполнения по таймеру
От: maks1180  
Дата: 12.01.22 21:11
Оценка:
ЕМ>В WinAPI вообще нет средств, позволяющих пользовательскому коду произвольно прерывать выполнение пользовательского же потока. Такое применяется в однопоточных системах, где невозможно организовать естественный параллелизм. В WinAPI переключение потока на пользовательский код возможно лишь в alertable-состоянии, в которое поток может войти только явно (например, через SleepEx и подобные функции).

будет ли поток в alertable-состоянии при нахождении внутри следующих функций ?
1) блокирующие функции WriteFile или ReadFile
2) получения списка файлов. Кажется FindNextFile.
===============================================
(реклама, удалена модератором)
Re[6]: прерываение выполнения по таймеру
От: maks1180  
Дата: 12.01.22 21:13
Оценка:
O>Ну вот вы аппелируете к сигналам, а вы в курсе, что список функций libc, которыми может пользоваться обработчик сигнала крайне ограничен? Даже printf'ом нельзя пользоваться, не говоря уж о malloc'е.

Нет не в курсе. malloc ещё понятно, не понятно почему printf'ом нельзя ?
===============================================
(реклама, удалена модератором)
Re[7]: прерываение выполнения по таймеру
От: ononim  
Дата: 12.01.22 21:16
Оценка:
O>>Ну вот вы аппелируете к сигналам, а вы в курсе, что список функций libc, которыми может пользоваться обработчик сигнала крайне ограничен? Даже printf'ом нельзя пользоваться, не говоря уж о malloc'е.
M>Нет не в курсе. malloc ещё понятно, не понятно почему printf'ом нельзя ?
Но там же по ссылке в третьем абзаце вот прямо на примере printf-а расписано почему
Как много веселых ребят, и все делают велосипед...
Re[3]: прерываение выполнения по таймеру
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 12.01.22 21:24
Оценка: +1
Здравствуйте, maks1180, Вы писали:

M>будет ли поток в alertable-состоянии при нахождении внутри следующих функций ?

M>1) блокирующие функции WriteFile или ReadFile

Нет. Можете использовать неблокирующие, за которыми сразу же идут функции alertable wait.

M>2) получения списка файлов. Кажется FindNextFile.


Разумеется, нет. С чего бы? Поток находится в состоянии alertable исключительно во время ожидания.

Я когда-то начинал делать асинхронные процессы и события на платформах, где нет многопоточности, и отсутствие прерываний в user-mode меня поначалу тоже удивляло. Но многопоточность позволяет все это делать в разы проще и надежнее, а главное — естественным образом ложится на современные многопроцессорные архитектуры. Делать что-то на средствах вроде сигналов сейчас имеет смысл исключительно с целью переноса на недоплатформы.
Re: прерываение выполнения по таймеру
От: AleksandrN Россия  
Дата: 12.01.22 21:24
Оценка:
Здравствуйте, maks1180, Вы писали:

M>В консольном приложение нужно прерывать выполнение кода регулярно, скажем 1 раз в секунду и вызывать свою функцию что-бы выводить статус.

M>Т.е. что-бы именно основной поток заходил в мою функцию, а не другой поток.

Откуда этот статус будет браться?
Почему именно в одном потоке это нужно?
Что делает основной поток, там в цикле что-то делается?

Опиши задачу целиком, может быть оптимально использовать какой-то другой механизм.
Re[8]: прерываение выполнения по таймеру
От: maks1180  
Дата: 12.01.22 21:26
Оценка:
O>Но там же по ссылке в третьем абзаце вот прямо на примере printf-а расписано почему

1) Да, прочитал. На эту тему у меня тоже был вопрос:
Можно ли указать участок коды выполнение которого нельзя прерывать ? Т.е. что-бы при заполнении струкруры данных, она либо полностью была заполнена либо ещё не тронута ?

2) Если выделить память в стеке, вызвать sprintf, потом получившуюся строку передать в write() так можно ?
===============================================
(реклама, удалена модератором)
Re: прерываение выполнения по таймеру
От: kov_serg Россия  
Дата: 12.01.22 21:31
Оценка:
Здравствуйте, maks1180, Вы писали:

M>В консольном приложение нужно прерывать выполнение кода регулярно, скажем 1 раз в секунду и вызывать свою функцию что-бы выводить статус.

А зачем для этого прерывать поток, что мешает завести еще один поток?

M>Т.е. что-бы именно основной поток заходил в мою функцию, а не другой поток.

распихайте по коду вызов функции yield() или еще как назовите.
и внутри неё вызывайте если что-то накопилось.

M>Можно ли указать участок коды выполнение которого нельзя прерывать? Т.е. что-бы при заполнении струкруры данных, она либо полностью была заполнена либо ещё не тронута.


M>В линукс прерывание по таймеру можно реализовать через сигналы.

M> signal(SIGALRM, sighandler); // Устанавливаем обработчик прерывания
M> alarm(5); // Задаём интервал 5 секунд

M>Как это можно сделать в Windows или кроссплатформенно ?

сделайте машины состояния и их можно будет итерировать в любом порядке
Re[9]: прерываение выполнения по таймеру
От: ononim  
Дата: 12.01.22 21:34
Оценка:
M>1) Да, прочитал. На эту тему у меня тоже был вопрос:
M>Можно ли указать участок коды выполнение которого нельзя прерывать ? Т.е. что-бы при заполнении струкруры данных, она либо полностью была заполнена либо ещё не тронута ?
Да, sigprocmask — но это будет изобретением синхронизации на коленке.

M>2) Если выделить память в стеке, вызвать sprintf, потом получившуюся строку передать в write() так можно ?

sprintf в списке по ссылке выше нету, так что лично я бы так не делал. write(1,.. ) — это выход, да. Если есть готовая строка.

Приведу пример из жизни. Есть у нас комплекс хардварно-софтварных автотестов, который измеряет в том числе общую производительность системы. Одним из тестов который он делает является вот этот нехитрый тулкит. Не невесть что, но адекватных попугаев выдает. Но была на заре становления комплекса с ним одна беда — раз в неделю..две зависал рандомный билд, в ходе исполнения этого теста. Когда надоело, и начали разбираться, оказалось что эта тулза делает как раз примерно что делаете вы: alarm и fprintf(stderr, и вот последний зависал, так как оказался вызванным из кишок какого другого printf.
Тулкит мы у себя переделали на перевод числа в строку врукопашную + write и проблема ушла.
Как много веселых ребят, и все делают велосипед...
Re[2]: прерываение выполнения по таймеру
От: maks1180  
Дата: 12.01.22 21:50
Оценка: -2 :))
M>>В консольном приложение нужно прерывать выполнение кода регулярно, скажем 1 раз в секунду и вызывать свою функцию что-бы выводить статус.
_>А зачем для этого прерывать поток, что мешает завести еще один поток?

Мешает, то что нужно будет делать синхронизацию данных и дополнительные блокировки, что снизит скорость.

M>>Т.е. что-бы именно основной поток заходил в мою функцию, а не другой поток.

_>распихайте по коду вызов функции yield() или еще как назовите.
_>и внутри неё вызывайте если что-то накопилось.
От безысходности, наверно придёться так делать.
Но тут если часто проверять нужно ли вызывать yield(), буду терять производительность. Если редко, то непонятно насколько реже нужно его вызывать, что-бы получить приемлемый результат.
В каждом курсе кода нужно будет мерить как часто проверять время, не пора ли вызвать yield().
===============================================
(реклама, удалена модератором)
Re[2]: прерываение выполнения по таймеру
От: maks1180  
Дата: 12.01.22 21:57
Оценка:
M>>В консольном приложение нужно прерывать выполнение кода регулярно, скажем 1 раз в секунду и вызывать свою функцию что-бы выводить статус.
M>>Т.е. что-бы именно основной поток заходил в мою функцию, а не другой поток.

AN>Откуда этот статус будет браться?

Из глобальных переменных.

AN>Почему именно в одном потоке это нужно?

Что-бы избежать синхронизации между потоками.

AN>Что делает основной поток, там в цикле что-то делается?

Да, считает хэш сумму файлов и копирует файлы при необходимости.

AN>Опиши задачу целиком, может быть оптимально использовать какой-то другой механизм.

Пока я хочу понять если ли такая возможность в Windows. Получается, что в Linux есть, а в Windows нет ?
===============================================
(реклама, удалена модератором)
Re[3]: прерываение выполнения по таймеру
От: ononim  
Дата: 12.01.22 22:25
Оценка:
AN>>Почему именно в одном потоке это нужно?
M>Что-бы избежать синхронизации между потоками.
Но но с сигналами надо тоже ее по сути делать — через sigprocmask и не факт что это будет быстрее. Точнее это будет точно медленнее чем обращение одной переменной через __sync_* чего достаточно судя по описанию проблемы.
Как много веселых ребят, и все делают велосипед...
Re[3]: прерываение выполнения по таймеру
От: kov_serg Россия  
Дата: 12.01.22 22:41
Оценка: +1
Здравствуйте, maks1180, Вы писали:

M>>>В консольном приложение нужно прерывать выполнение кода регулярно, скажем 1 раз в секунду и вызывать свою функцию что-бы выводить статус.

_>>А зачем для этого прерывать поток, что мешает завести еще один поток?

M>Мешает, то что нужно будет делать синхронизацию данных и дополнительные блокировки, что снизит скорость.

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

M>От безысходности, наверно придёться так делать.

M>Но тут если часто проверять нужно ли вызывать yield(), буду терять производительность. Если редко, то непонятно насколько реже нужно его вызывать, что-бы получить приемлемый результат.
Что бы было быстро надо выполнять действия не по одному, а партиями по 2-3 млн шт

M>В каждом курсе кода нужно будет мерить как часто проверять время, не пора ли вызвать yield().

Вообще-то можно сделать предварительный делитель например
if (++counter>divided) { counter=0; action(); }
или лучше разбить на батчи
Re[2]: прерываение выполнения по таймеру
От: Cyberax Марс  
Дата: 13.01.22 06:09
Оценка: -1
Здравствуйте, Евгений Музыченко, Вы писали:

M>>что-бы именно основной поток заходил в мою функцию, а не другой поток.

M>>Можно ли указать участок коды выполнение которого нельзя прерывать ?
ЕМ>В WinAPI вообще нет средств, позволяющих пользовательскому коду произвольно прерывать выполнение пользовательского же потока.
Существует:
https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-queueuserapc
Sapienti sat!
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.