В консольном приложение нужно прерывать выполнение кода регулярно, скажем 1 раз в секунду и вызывать свою функцию что-бы выводить статус.
Т.е. что-бы именно основной поток заходил в мою функцию, а не другой поток.
Можно ли указать участок коды выполнение которого нельзя прерывать ? Т.е. что-бы при заполнении струкруры данных, она либо полностью была заполнена либо ещё не тронута.
В линукс прерывание по таймеру можно реализовать через сигналы.
signal(SIGALRM, sighandler); // Устанавливаем обработчик прерывания
alarm(5); // Задаём интервал 5 секунд
Как это можно сделать в Windows или кроссплатформенно ?
Здравствуйте, maks1180, Вы писали:
M>что-бы именно основной поток заходил в мою функцию, а не другой поток. M>Можно ли указать участок коды выполнение которого нельзя прерывать ?
В WinAPI вообще нет средств, позволяющих пользовательскому коду произвольно прерывать выполнение пользовательского же потока. Такое применяется в однопоточных системах, где невозможно организовать естественный параллелизм. В WinAPI переключение потока на пользовательский код возможно лишь в alertable-состоянии, в которое поток может войти только явно (например, через SleepEx и подобные функции).
Произвольно прерывать поток может только ядерный код.
ЕМ>Произвольно прерывать поток может только ядерный код.
Ну да, ядерный код, должен в определённое время прервать определённый поток и передать выполнение заранее определённой функции.
Осталось найти WinAPI функции, что-бы сообщить это ядру.
Здравствуйте, maks1180, Вы писали:
M>Почему хорошо ?
Потому, что поддержка прерываний еще и на уровне пользовательского кода — это дополнительный геморрой по хранению правил переходов, текущих состояний, предоставлению примитивов по управлению всем этим, а для чего? Повторю: эти техники используются от бедности отсутствия нормальной, человеческой многопоточности, которая позволяет коду автоматически масштабироваться между одним процессором и бесконечностью их.
ЕМ>>Я же сказал — ее не существует. И это очень хорошо. M>Почему хорошо ?
Ну вот вы аппелируете к сигналам, а вы в курсе, что список функций libc, которыми может пользоваться обработчик сигнала крайне ограничен? Даже printf'ом нельзя пользоваться, не говоря уж о malloc'е. А если оно у вас работает, то это благодаря высокому уровню удачи. Реально самый адекватный способ работы с сигналами — это блокировать их все нахрен, и крутить sigwait или же signalfd + select/poll. То есть по сути — аналог alertable wait.
Как много веселых ребят, и все делают велосипед...
ЕМ>В WinAPI вообще нет средств, позволяющих пользовательскому коду произвольно прерывать выполнение пользовательского же потока. Такое применяется в однопоточных системах, где невозможно организовать естественный параллелизм. В WinAPI переключение потока на пользовательский код возможно лишь в alertable-состоянии, в которое поток может войти только явно (например, через SleepEx и подобные функции).
будет ли поток в alertable-состоянии при нахождении внутри следующих функций ?
1) блокирующие функции WriteFile или ReadFile
2) получения списка файлов. Кажется FindNextFile.
O>Ну вот вы аппелируете к сигналам, а вы в курсе, что список функций libc, которыми может пользоваться обработчик сигнала крайне ограничен? Даже printf'ом нельзя пользоваться, не говоря уж о malloc'е.
Нет не в курсе. malloc ещё понятно, не понятно почему printf'ом нельзя ?
O>>Ну вот вы аппелируете к сигналам, а вы в курсе, что список функций libc, которыми может пользоваться обработчик сигнала крайне ограничен? Даже printf'ом нельзя пользоваться, не говоря уж о malloc'е. M>Нет не в курсе. malloc ещё понятно, не понятно почему printf'ом нельзя ?
Но там же по ссылке в третьем абзаце вот прямо на примере printf-а расписано почему
Как много веселых ребят, и все делают велосипед...
Здравствуйте, maks1180, Вы писали:
M>будет ли поток в alertable-состоянии при нахождении внутри следующих функций ? M>1) блокирующие функции WriteFile или ReadFile
Нет. Можете использовать неблокирующие, за которыми сразу же идут функции alertable wait.
M>2) получения списка файлов. Кажется FindNextFile.
Разумеется, нет. С чего бы? Поток находится в состоянии alertable исключительно во время ожидания.
Я когда-то начинал делать асинхронные процессы и события на платформах, где нет многопоточности, и отсутствие прерываний в user-mode меня поначалу тоже удивляло. Но многопоточность позволяет все это делать в разы проще и надежнее, а главное — естественным образом ложится на современные многопроцессорные архитектуры. Делать что-то на средствах вроде сигналов сейчас имеет смысл исключительно с целью переноса на недоплатформы.
Здравствуйте, maks1180, Вы писали:
M>В консольном приложение нужно прерывать выполнение кода регулярно, скажем 1 раз в секунду и вызывать свою функцию что-бы выводить статус. M>Т.е. что-бы именно основной поток заходил в мою функцию, а не другой поток.
Откуда этот статус будет браться?
Почему именно в одном потоке это нужно?
Что делает основной поток, там в цикле что-то делается?
Опиши задачу целиком, может быть оптимально использовать какой-то другой механизм.
O>Но там же по ссылке в третьем абзаце вот прямо на примере printf-а расписано почему
1) Да, прочитал. На эту тему у меня тоже был вопрос:
Можно ли указать участок коды выполнение которого нельзя прерывать ? Т.е. что-бы при заполнении струкруры данных, она либо полностью была заполнена либо ещё не тронута ?
2) Если выделить память в стеке, вызвать sprintf, потом получившуюся строку передать в write() так можно ?
Здравствуйте, maks1180, Вы писали:
M>В консольном приложение нужно прерывать выполнение кода регулярно, скажем 1 раз в секунду и вызывать свою функцию что-бы выводить статус.
А зачем для этого прерывать поток, что мешает завести еще один поток?
M>Т.е. что-бы именно основной поток заходил в мою функцию, а не другой поток.
распихайте по коду вызов функции yield() или еще как назовите.
и внутри неё вызывайте если что-то накопилось.
M>Можно ли указать участок коды выполнение которого нельзя прерывать? Т.е. что-бы при заполнении струкруры данных, она либо полностью была заполнена либо ещё не тронута.
M>В линукс прерывание по таймеру можно реализовать через сигналы. M> signal(SIGALRM, sighandler); // Устанавливаем обработчик прерывания M> alarm(5); // Задаём интервал 5 секунд
M>Как это можно сделать в Windows или кроссплатформенно ?
сделайте машины состояния и их можно будет итерировать в любом порядке
M>1) Да, прочитал. На эту тему у меня тоже был вопрос: M>Можно ли указать участок коды выполнение которого нельзя прерывать ? Т.е. что-бы при заполнении струкруры данных, она либо полностью была заполнена либо ещё не тронута ?
Да, sigprocmask — но это будет изобретением синхронизации на коленке.
M>2) Если выделить память в стеке, вызвать sprintf, потом получившуюся строку передать в write() так можно ?
sprintf в списке по ссылке выше нету, так что лично я бы так не делал. write(1,.. ) — это выход, да. Если есть готовая строка.
Приведу пример из жизни. Есть у нас комплекс хардварно-софтварных автотестов, который измеряет в том числе общую производительность системы. Одним из тестов который он делает является вот этот нехитрый тулкит. Не невесть что, но адекватных попугаев выдает. Но была на заре становления комплекса с ним одна беда — раз в неделю..две зависал рандомный билд, в ходе исполнения этого теста. Когда надоело, и начали разбираться, оказалось что эта тулза делает как раз примерно что делаете вы: alarm и fprintf(stderr, и вот последний зависал, так как оказался вызванным из кишок какого другого printf.
Тулкит мы у себя переделали на перевод числа в строку врукопашную + write и проблема ушла.
Как много веселых ребят, и все делают велосипед...
M>>В консольном приложение нужно прерывать выполнение кода регулярно, скажем 1 раз в секунду и вызывать свою функцию что-бы выводить статус. _>А зачем для этого прерывать поток, что мешает завести еще один поток?
Мешает, то что нужно будет делать синхронизацию данных и дополнительные блокировки, что снизит скорость.
M>>Т.е. что-бы именно основной поток заходил в мою функцию, а не другой поток. _>распихайте по коду вызов функции yield() или еще как назовите. _>и внутри неё вызывайте если что-то накопилось.
От безысходности, наверно придёться так делать.
Но тут если часто проверять нужно ли вызывать yield(), буду терять производительность. Если редко, то непонятно насколько реже нужно его вызывать, что-бы получить приемлемый результат.
В каждом курсе кода нужно будет мерить как часто проверять время, не пора ли вызвать yield().
M>>В консольном приложение нужно прерывать выполнение кода регулярно, скажем 1 раз в секунду и вызывать свою функцию что-бы выводить статус. M>>Т.е. что-бы именно основной поток заходил в мою функцию, а не другой поток.
AN>Откуда этот статус будет браться?
Из глобальных переменных.
AN>Почему именно в одном потоке это нужно?
Что-бы избежать синхронизации между потоками.
AN>Что делает основной поток, там в цикле что-то делается?
Да, считает хэш сумму файлов и копирует файлы при необходимости.
AN>Опиши задачу целиком, может быть оптимально использовать какой-то другой механизм.
Пока я хочу понять если ли такая возможность в Windows. Получается, что в Linux есть, а в Windows нет ?
AN>>Почему именно в одном потоке это нужно? M>Что-бы избежать синхронизации между потоками.
Но но с сигналами надо тоже ее по сути делать — через sigprocmask и не факт что это будет быстрее. Точнее это будет точно медленнее чем обращение одной переменной через __sync_* чего достаточно судя по описанию проблемы.
Как много веселых ребят, и все делают велосипед...
Здравствуйте, maks1180, Вы писали:
M>>>В консольном приложение нужно прерывать выполнение кода регулярно, скажем 1 раз в секунду и вызывать свою функцию что-бы выводить статус. _>>А зачем для этого прерывать поток, что мешает завести еще один поток?
M>Мешает, то что нужно будет делать синхронизацию данных и дополнительные блокировки, что снизит скорость.
Это собственно говоря почему?
Вопервых надо уведомлять о прогрессе не постоянно, а после группы проделанных операций или с задержкой (например не чаще 10 раз в сек)
Во вторых вывод прогресса это не столь ресурсоёмкая часть.
M>От безысходности, наверно придёться так делать. M>Но тут если часто проверять нужно ли вызывать yield(), буду терять производительность. Если редко, то непонятно насколько реже нужно его вызывать, что-бы получить приемлемый результат.
Что бы было быстро надо выполнять действия не по одному, а партиями по 2-3 млн шт
M>В каждом курсе кода нужно будет мерить как часто проверять время, не пора ли вызвать yield().
Вообще-то можно сделать предварительный делитель например
Здравствуйте, Евгений Музыченко, Вы писали:
M>>что-бы именно основной поток заходил в мою функцию, а не другой поток. M>>Можно ли указать участок коды выполнение которого нельзя прерывать ? ЕМ>В WinAPI вообще нет средств, позволяющих пользовательскому коду произвольно прерывать выполнение пользовательского же потока.
Существует: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-queueuserapc