AG>>В общем авто-магии не получится. Все проблемы интерапшинов из boost::thread будут. GC>Не работал с boost.thread. А он, что, поддерживает прерываемость?
boost::thread похож на std::thread (ибо был прототипом std::thread), но имеет расширения, одно из — интеррапшин поинты.
Любая точка прерывания бросает thread_interrupted исключение, если поток прервали.
Точками прерывания являются явные вызовы interruption_point.
Кроме того, некоторые ожидания: sleep, условной переменной, join — всё является точками прерывания.
То есть, если поток сейчас ждёт мьютекс ждёт на условной переменной, и его прервали, он вылетит тут же.
Разумеется, работает только с примитивами из boost, в них заложено ожидание на событии прерывания одновременно с основным ожиданием.
Для борьбы с исключениями в деструкторах создают на стеке disable_interruption.
Для борьбы с борьбой с исключениями создают на стеке restore_interruption.
thread_interrupted исключение целенаправленно не наследуется от std::exception, чтобы оно прошло через все catch(std::exception&) и завершило thread.
Но если в треде есть catch(...), то он съест thread_interrupted исключение, и вместо полного прерывания нити будет просто раскрутка до этого catch(...)
GC>То есть, я думаю что это нельзя сделать в compile-time при помощи одного С++. Только расширение, основанное на Clang писать?
На данный момент нет, вроде ничего такого нет.
Может, препроцессором?
Были пропозл по метаклассам, должен решать кодогенерационные задачи.
Для кодогенерации не привязанной к конкретному классу там были namespace class. My namespace — my rules
Только не факт, что зайдёт, и что он в финале будет достаточно упорот, чтобы не просто генерировать методы, а изменять существующие методы.
Здравствуйте, GhostCoders, Вы писали:
GC>Естественно, такие методы становятся бросающими исключениями.
А потом будет цикл который вызывается из деструктора, там надо будет запретить исключения, потом ещё с catch(...) бороться.
В общем авто-магии не получится. Все проблемы интерапшинов из boost::thread будут.
Так, подозреваю, даже без расширения компилятора сделать можно такое:
Здравствуйте, GhostCoders, Вы писали:
GC>Вручную такие методы писать утомительно. GC>Что скажите?
Скажу: вы обленились. И для обработки данных вам нужен SQL подобный язык котрый будет строить план выполнения запроса и выполнять его, отчитываясь о проделанной работе.
progress_helper осуществляет репорт текущего прогресса в % при помощи колбэка, а также проверяет значение из колбэка,
надо ли прервать выполнение функции или нет. Если надо, то выбрасывает некое специальное исключение.
Вручную такие методы писать утомительно.
Я вот думаю, что если сделать на базе clang свое расширение компилятора, которые
дя заданных методов автоматически вставляло нужные объявления progress_helper?
Естественно, такие методы становятся бросающими исключениями.
Здравствуйте, Alexander G, Вы писали:
AG>А потом будет цикл который вызывается из деструктора, там надо будет запретить исключения, потом ещё с catch(...) бороться.
В деструкторе — да, исключения запретить, но репорт прогресса нужно оставить.
А с catch(...) нужно ли еще как-то бороться дополнительно?
AG>В общем авто-магии не получится. Все проблемы интерапшинов из boost::thread будут.
Не работал с boost.thread. А он, что, поддерживает прерываемость?
AG>Так, подозреваю, даже без расширения компилятора сделать можно такое: AG>
Плагин с Clang (расширение) вычислит что в функции process_student() 3 линейных вызова других метода,
и поэтому вставит инициализацию progress_helper student_progress(3); с константным числом 3 (времени компиляции).
Вообще, интересно, возможно такое (вычислить число вызовов функций) в compile-time через шаблоны или еще как-то? Ну использовать макросы что-то в духе
GC>Что скажите?
Примени MVC в некотором усечённом виде, в принципе у тебя как раз та задача которая и решается им: отделение логики от представления данных (прогресс бар). Если использовать два потока, один на алгоритм, другой на UI, то всё будет работать. Можно попробовать использовать корутины для обновления и отображения счётчика.
Здравствуйте, Kernan, Вы писали:
K>Примени MVC в некотором усечённом виде, в принципе у тебя как раз та задача которая и решается им: отделение логики от представления данных (прогресс бар). Если использовать два потока, один на алгоритм, другой на UI, то всё будет работать. Можно попробовать использовать корутины для обновления и отображения счётчика.
Не совсем представляю, как это можно отделить. Какой-нибудь пример?
Здравствуйте, GhostCoders, Вы писали:
GC>Здравствуйте, Kernan, Вы писали:
K>>Примени MVC в некотором усечённом виде, в принципе у тебя как раз та задача которая и решается им: отделение логики от представления данных (прогресс бар). Если использовать два потока, один на алгоритм, другой на UI, то всё будет работать. Можно попробовать использовать корутины для обновления и отображения счётчика. GC>Не совсем представляю, как это можно отделить. Какой-нибудь пример?
Смотри, данные о студентах/классах у тебя лежат в моделе, там же некий счёткик прогресса который обновляется после итерации обработки, в контроллере у тебя лежит логика обработки где этот счётчки разумным образом увеличивается, вид это некий тред UI который по событию изменения модели (счётчика) будет рисовать его на экране, как вариант можно по тймеру в UI треде вычитывать значенеи счётчика и рисовать его. Для этой задачи interruption point-ы это оверкилл.
Здравствуйте, Kernan, Вы писали:
K>Смотри, данные о студентах/классах у тебя лежат в моделе, там же некий счёткик прогресса который обновляется после итерации обработки, в контроллере у тебя лежит логика обработки где этот счётчки разумным образом увеличивается, вид это некий тред UI который по событию изменения модели (счётчика) будет рисовать его на экране, как вариант можно по тймеру в UI треде вычитывать значенеи счётчика и рисовать его. Для этой задачи interruption point-ы это оверкилл.
Особо не вникнул. Но почему оверкилл? Пользователь нажал кнопочку Cancel, и хочет чтобы длительная процедура обработки школ\классов\студентов прервалась.
Да, UI в одном потоке, вычисления в другом. Но жестко прибивать поток с вычислениями — не айс. Как быть?
Здравствуйте, kov_serg, Вы писали:
_>Скажу: вы обленились.
Так можно сказать и про тех, кто пользуется исключениями. Мол, обленились возвращать коды ошибок и проверять коды ошибок из вызываемых методов
Здравствуйте, Alexander G, Вы писали:
AG>... AG>Разумеется, работает только с примитивами из boost, в них заложено ожидание на событии прерывания одновременно с основным ожиданием.
Спасибо за информацию!
AG>thread_interrupted исключение целенаправленно не наследуется от std::exception, чтобы оно прошло через все catch(std::exception&) и завершило thread. AG>Но если в треде есть catch(...), то он съест thread_interrupted исключение, и вместо полного прерывания нити будет просто раскрутка до этого catch(...)
Кстати, расширение для Clang может решить это проблему. Анализировать код, и если есть catch(...), то вставлять чуть выше catch(const thread_interrupted&) и заново его перевыбрасывать.
В результате thread_interrupted будет проходить мимо catch (...).
AG>Для борьбы с исключениями в деструкторах создают на стеке disable_interruption. AG>Для борьбы с борьбой с исключениями создают на стеке restore_interruption.
Расширение Clang не будет генерировать выброс исключений в деструкторах.
Да и вообще через расширение Clang больше возможностей.
Здравствуйте, GhostCoders, Вы писали:
GC>Расширение Clang не будет генерировать выброс исключений в деструкторах.
Тут, видимо придётся запоминать в per-thread контексте, что мы в деструкторе, и не выбрасывать исключения.
Просто непосредственно из десткрутора запретить недостаточно, деструктор же тоже может вызывать методы.
В целом, это уже будет похоже на .NET-овские Thread.Abort Method / ThreadAbortException.
Там точки, откуда может вылететь ThreadAbortException — повсюду, кроме нативного кода.
Ну и из finally блока, вызванного при раскрутке, оно не вылетит (аналог С++ деструктора).
С таким подходом возникают проблемы именно из-за того, что исключение может возникнуть в любом месте.
Как оказывается, не весь код обеспечивает базовую гарантию исключений.
Утечки любых не-RAII ресурсов, застревание объектов в запрещённых состояниях и т.д.
Вот например есть шаблонный контейнер vector, который при уменьшающем resize вызывает деструкторы в цикле, что, если этот цикл прервать?