Автопрогресс и автопрерываемость в С++
От: GhostCoders Россия  
Дата: 21.03.18 05:34
Оценка:
Навеяно моим постом — http://rsdn.org/forum/cpp.applied/7053719.1
Автор: GhostCoders
Дата: 13.02.18


Суть в том, что необходимо внутрь каждого "долгого" метода вставлять объявление progress_helper класса, например так:
void process_class(Class& class_)
{
    progress_helper class_progress(school.get_student_count());
    for(student: class_)
    {
        process_student(student);
        class_progress.step();
    }
}

progress_helper осуществляет репорт текущего прогресса в % при помощи колбэка, а также проверяет значение из колбэка,
надо ли прервать выполнение функции или нет. Если надо, то выбрасывает некое специальное исключение.

Вручную такие методы писать утомительно.
Я вот думаю, что если сделать на базе clang свое расширение компилятора, которые
дя заданных методов автоматически вставляло нужные объявления progress_helper?
Естественно, такие методы становятся бросающими исключениями.

Код:
void process_school(School& school) auto_progress
{
    for(class: school.classes())
    {
        process_class(class);
    }
}
void process_class(Class& class_) auto_progress
{
    for(student: class_)
    {
        process_student(student);
    }
}
void process_stundent(Student& student) auto_progress
{
    process_name(student.name);
    process_surname(student.surname);
    process_sex(student.sex);
}


превращается в
void process_school(School& school)
{
    progress_helper school_progress(school.get_class_count());
    for(class: school.classes())
    {
        process_class(class);
        school_progress.step();
    }
}
void process_class(Class& class_)
{
    progress_helper class_progress(school.get_student_count());
    for(student: class_)
    {
        process_student(student);
        class_progress.step();
    }
}
void process_stundent(Student& student)
{
    progress_helper student_progress(3);
    process_name(student.name);
    student_progress.step();
    process_surname(student.surname);
    student_progress.step();
    process_sex(student.sex);
    student_progress.step();
}


Что скажите?
Третий Рим должен пасть!
Re: Автопрогресс и автопрерываемость в С++
От: Alexander G Украина  
Дата: 21.03.18 05:58
Оценка: 2 (1)
Здравствуйте, GhostCoders, Вы писали:

GC>Естественно, такие методы становятся бросающими исключениями.


А потом будет цикл который вызывается из деструктора, там надо будет запретить исключения, потом ещё с catch(...) бороться.
В общем авто-магии не получится. Все проблемы интерапшинов из boost::thread будут.

Так, подозреваю, даже без расширения компилятора сделать можно такое:

for(class: interruption_points_adapter(school.classes()))
{
...
}


адаптер завернёт it++ в проверку.
Русский военный корабль идёт ко дну!
Re[2]: Автопрогресс и автопрерываемость в С++
От: GhostCoders Россия  
Дата: 21.03.18 08:13
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>А потом будет цикл который вызывается из деструктора, там надо будет запретить исключения, потом ещё с catch(...) бороться.

В деструкторе — да, исключения запретить, но репорт прогресса нужно оставить.
А с catch(...) нужно ли еще как-то бороться дополнительно?

AG>В общем авто-магии не получится. Все проблемы интерапшинов из boost::thread будут.

Не работал с boost.thread. А он, что, поддерживает прерываемость?

AG>Так, подозреваю, даже без расширения компилятора сделать можно такое:

AG>
AG>for(class: interruption_points_adapter(school.classes()))
AG>{
AG>...
AG>}
AG>

AG>адаптер завернёт it++ в проверку.
Да, можно. Но прогресс не только по циклам. А по линейным операторам типа:

void process_stundent(Student& student) auto_progress
{
    process_name(student.name);
    process_surname(student.surname);
    process_sex(student.sex);
}
// который превращается в
void process_stundent(Student& student)
{
    progress_helper student_progress(3);
    process_name(student.name);
    student_progress.step();
    process_surname(student.surname);
    student_progress.step();
    process_sex(student.sex);
    student_progress.step();
}


Плагин с Clang (расширение) вычислит что в функции process_student() 3 линейных вызова других метода,
и поэтому вставит инициализацию progress_helper student_progress(3); с константным числом 3 (времени компиляции).
Вообще, интересно, возможно такое (вычислить число вызовов функций) в compile-time через шаблоны или еще как-то? Ну использовать макросы что-то в духе
void process_stundent(Student& student)
{
    PROGRESS_STEP(process_name(student.name));
    PROGRESS_STEP(process_surname(student.surname));
    PROGRESS_STEP(process_sex(student.sex));
}

не вариант.

То есть, я думаю что это нельзя сделать в compile-time при помощи одного С++. Только расширение, основанное на Clang писать?
Третий Рим должен пасть!
Re: Автопрогресс и автопрерываемость в С++
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 21.03.18 08:41
Оценка:
Здравствуйте, GhostCoders, Вы писали:

GC>Навеяно моим постом — http://rsdn.org/forum/cpp.applied/7053719.1
Автор: GhostCoders
Дата: 13.02.18

GC>Что скажите?
Примени MVC в некотором усечённом виде, в принципе у тебя как раз та задача которая и решается им: отделение логики от представления данных (прогресс бар). Если использовать два потока, один на алгоритм, другой на UI, то всё будет работать. Можно попробовать использовать корутины для обновления и отображения счётчика.
Sic luceat lux!
Re[3]: Автопрогресс и автопрерываемость в С++
От: Alexander G Украина  
Дата: 21.03.18 08:52
Оценка: 6 (1)
Здравствуйте, GhostCoders, Вы писали:


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

Только не факт, что зайдёт, и что он в финале будет достаточно упорот, чтобы не просто генерировать методы, а изменять существующие методы.
Русский военный корабль идёт ко дну!
Отредактировано 21.03.2018 9:36 Alexander G . Предыдущая версия .
Re[2]: Автопрогресс и автопрерываемость в С++
От: GhostCoders Россия  
Дата: 21.03.18 12:01
Оценка:
Здравствуйте, Kernan, Вы писали:

K>Примени MVC в некотором усечённом виде, в принципе у тебя как раз та задача которая и решается им: отделение логики от представления данных (прогресс бар). Если использовать два потока, один на алгоритм, другой на UI, то всё будет работать. Можно попробовать использовать корутины для обновления и отображения счётчика.

Не совсем представляю, как это можно отделить. Какой-нибудь пример?
Третий Рим должен пасть!
Re[3]: Автопрогресс и автопрерываемость в С++
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 21.03.18 15:22
Оценка:
Здравствуйте, GhostCoders, Вы писали:

GC>Здравствуйте, Kernan, Вы писали:


K>>Примени MVC в некотором усечённом виде, в принципе у тебя как раз та задача которая и решается им: отделение логики от представления данных (прогресс бар). Если использовать два потока, один на алгоритм, другой на UI, то всё будет работать. Можно попробовать использовать корутины для обновления и отображения счётчика.

GC>Не совсем представляю, как это можно отделить. Какой-нибудь пример?
Смотри, данные о студентах/классах у тебя лежат в моделе, там же некий счёткик прогресса который обновляется после итерации обработки, в контроллере у тебя лежит логика обработки где этот счётчки разумным образом увеличивается, вид это некий тред UI который по событию изменения модели (счётчика) будет рисовать его на экране, как вариант можно по тймеру в UI треде вычитывать значенеи счётчика и рисовать его. Для этой задачи interruption point-ы это оверкилл.
Sic luceat lux!
Re[4]: Автопрогресс и автопрерываемость в С++
От: GhostCoders Россия  
Дата: 21.03.18 15:29
Оценка:
Здравствуйте, Kernan, Вы писали:

K>Смотри, данные о студентах/классах у тебя лежат в моделе, там же некий счёткик прогресса который обновляется после итерации обработки, в контроллере у тебя лежит логика обработки где этот счётчки разумным образом увеличивается, вид это некий тред UI который по событию изменения модели (счётчика) будет рисовать его на экране, как вариант можно по тймеру в UI треде вычитывать значенеи счётчика и рисовать его. Для этой задачи interruption point-ы это оверкилл.

Особо не вникнул. Но почему оверкилл? Пользователь нажал кнопочку Cancel, и хочет чтобы длительная процедура обработки школ\классов\студентов прервалась.
Да, UI в одном потоке, вычисления в другом. Но жестко прибивать поток с вычислениями — не айс. Как быть?
Третий Рим должен пасть!
Re: Автопрогресс и автопрерываемость в С++
От: kov_serg Россия  
Дата: 21.03.18 18:09
Оценка: +1
Здравствуйте, GhostCoders, Вы писали:

GC>Вручную такие методы писать утомительно.

GC>Что скажите?
Скажу: вы обленились. И для обработки данных вам нужен SQL подобный язык котрый будет строить план выполнения запроса и выполнять его, отчитываясь о проделанной работе.
Re[2]: Автопрогресс и автопрерываемость в С++
От: GhostCoders Россия  
Дата: 23.03.18 11:34
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Скажу: вы обленились.

Так можно сказать и про тех, кто пользуется исключениями. Мол, обленились возвращать коды ошибок и проверять коды ошибок из вызываемых методов
Третий Рим должен пасть!
Re[4]: Автопрогресс и автопрерываемость в С++
От: GhostCoders Россия  
Дата: 23.03.18 11:41
Оценка:
Здравствуйте, 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 больше возможностей.
Третий Рим должен пасть!
Re[5]: Автопрогресс и автопрерываемость в С++
От: Alexander G Украина  
Дата: 23.03.18 13:09
Оценка:
Здравствуйте, GhostCoders, Вы писали:

GC>Расширение Clang не будет генерировать выброс исключений в деструкторах.


Тут, видимо придётся запоминать в per-thread контексте, что мы в деструкторе, и не выбрасывать исключения.
Просто непосредственно из десткрутора запретить недостаточно, деструктор же тоже может вызывать методы.

В целом, это уже будет похоже на .NET-овские Thread.Abort Method / ThreadAbortException.
Там точки, откуда может вылететь ThreadAbortException — повсюду, кроме нативного кода.
Ну и из finally блока, вызванного при раскрутке, оно не вылетит (аналог С++ деструктора).

С таким подходом возникают проблемы именно из-за того, что исключение может возникнуть в любом месте.
Как оказывается, не весь код обеспечивает базовую гарантию исключений.
Утечки любых не-RAII ресурсов, застревание объектов в запрещённых состояниях и т.д.

Вот например есть шаблонный контейнер vector, который при уменьшающем resize вызывает деструкторы в цикле, что, если этот цикл прервать?
Русский военный корабль идёт ко дну!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.