![]() |
![]() ![]() ![]() ![]() ![]() |
![]() |
Class execution_context (version 1)Boost , Chapter 1. Context , Chapter 1. Context
|
![]() |
Note |
---|---|
Этот класс включается только в том случае, если свойство segmented-stacks=on (включает сегментированные стеки) или флаг компилятора BOOST_EXECUTION_CONTEXT=1 указывается в b2-командной строке. |
Класс execution_context инкапсулирует переключение контекста и управляет стеком связанного контекста (выделение/выделение).
execution_context выделяет контекстный стек (используя его аргумент StackAllocator) и создает поверх него управляющую структуру. Эта структура отвечает за управление стеком контекста. Случаи execution_context, связанные с конкретным контекстом, разделяют право собственности на структуру управления. Если последняя ссылка выходит из области действия, структура управления разрушается, и стек размещается через StackAllocator.
execution_context является копируемым, подвижным, копируемым и подвижным.
execution_context поддерживает статический (потоковый) указатель, доступный по execution_context::current(), указывая на активный контекст. На каждом переключателе контекста указатель обновляется. Использование этого глобального указателя делает переключение контекста немного медленнее (из-за доступа к локальному хранилищу потоков), но имеет некоторые преимущества. Он позволяет получить доступ к структуре управления текущим активным контекстом из произвольных путей кода, необходимых для поддержки сегментированных стеков, которые требуют вызова определенных функций обслуживания (например, __splitstack_getcontext() и т. д.) перед каждым коммутатором контекста (каждый коммутатор контекста обменивается стеком).
execution_context ожидает функцию/функтор с подписью void( vp)
(vp
- данные, переданные при первом вызове ecv1::operator()()
).
int n=35; boost::context::execution_context sink(boost::context::execution_context::current()); boost::context::execution_context source( [n,&sink](void*)mutable{ int a=0; int b=1; while(n-->0){ sink(&a); auto next=a+b; a=b; b=next; } }); for(int i=0;i<10;++i){ std::cout<<*(int*)source()<<" "; } output: 0 1 1 2 3 5 8 13 21 34
Этот простой пример демонстрирует основное использование execution_context. Контекст sink
, возвращаемый execution_context::current(), представляет собой main-context (функция main() run) и является одним из захваченных параметров в лямбда-выражении. Ламбда, вычисляющая числа Фибоначчи, выполняется внутри контекста, представленного источником
. Вычисленные числа Фибоначчи переносятся между двумя контекстами через выражение sink(&a) (и возвращаются source()).
Локальные переменные a
, b
и next
остаются их значениями во время каждого контекстного переключателя (yield(a)). Это возможно, потому что ctx
имеет стек (обмен с помощью переключателя контекста).
/* * grammar: * P ---> E '\0' * E ---> T {('+'|'-') T} * T ---> S {('*'|'/') S} * S ---> digit | '(' E ')' */ class Parser{ // implementation omitted; see examples directory }; std::istringstream is("1+1"); bool done=false; std::exception_ptr except; // create handle to main execution context auto main_ctx(boost::context::execution_context::current()); // execute parser in new execution context boost::context::execution_context source( [&sink,&is,&done,&except](void*){ // create parser with callback function Parser p(is, [&sink](char ch){ // resume main execution context sink(&ch); }); try { // start recursive parsing p.run(); } catch (...) { // store other exceptions in exception-pointer except = std::current_exception(); } // set termination flag done=true; // resume main execution context sink(); }); // user-code pulls parsed data from parser // invert control flow void* vp = source(); if (except) { std::rethrow_exception(except); } while( ! done) { printf("Parsed: %c\n",* static_cast<char*>(vp)); vp = source(); if (except) { std::rethrow_exception(except); } } output: Parsed: 1 Parsed: + Parsed: 1
В этом примере рекурсивный парсер спуска использует обратный вызов, чтобы излучать недавно принятый символ. Используя execution_context, поток управления может быть инвертирован, например, пользовательский код извлекает парсированные символы из парсера - вместо этого, чтобы получить выталкивание из парсера (через обратный вызов).
Данные (характер) передаются между двумя execution_context.
Если код, выполненный execution_context, испускает исключение, приложение прекращается. std:: Exception_ptr может использоваться для передачи исключений между различными контекстами исполнения.
Иногда необходимо раскручивать стек незавершенного контекста, чтобы уничтожить локальные переменные стека, чтобы они могли высвобождать выделенные ресурсы (паттерн RAII). Пользователь несет ответственность за эту задачу.
Выделение структур управления поверх стека требует выделения stack_context и создания новой структуры управления с размещением до создания execution_context.
![]() |
Note |
---|---|
Пользователь несет ответственность за разрушение структуры управления в верхней части стека. |
// stack-allocator used for (de-)allocating stack fixedsize_stack salloc( 4048); // allocate stack space stack_context sctx( salloc.allocate() ); // reserve space for control structure on top of the stack void * sp = static_cast< char * >( sctx.sp) - sizeof( my_control_structure); std::size_t size = sctx.size - sizeof( my_control_structure); // placement new creates control structure on reserved space my_control_structure * cs = new ( sp) my_control_structure( sp, size, sctx, salloc); ... // destructing the control structure cs->~my_control_structure(); ... struct my_control_structure { // execution context execution_context ectx; template< typename StackAllocator > my_control_structure( void * sp, std::size_t size, stack_context sctx, StackAllocator salloc) : // create execution context ectx( std::allocator_arg, preallocated( sp, size, sctx), salloc, entry_func) { } ... };
Если функция, выполненная внутри execution_context, испускает исключение, приложение завершается вызовом std::terminate(). std:: Exception_ptr может использоваться для передачи исключений между различными контекстами исполнения.
![]() |
Important |
---|---|
Не прыгайте изнутри блок-уловки, а затем повторно бросайте исключение в другой контекст исполнения. |
Аргумент void pointer передан execution_context::operator(), в одном контексте, передается как последний аргумент context-function, если контекст запущен впервые. Во всех следующих вызовах execution_context::operator() указатель пустоты, переданный execution_context::operator(), в одном контексте возвращается execution_context::operator() в другом контексте.
class X { private: std::exception_ptr excptr_; boost::context::execution_context caller_; boost::context::execution_context callee_; public: X() : excptr_(), caller_( boost::context::execution_context::current() ), callee_( [=] (void * vp) { try { int i = * static_cast< int * >( vp); std::string str = boost::lexical_cast<std::string>(i); caller_( & str); } catch (std::bad_cast const&) { excptr_=std::current_exception(); } }) {} std::string operator()( int i) { void * ret = callee_( & i); if(excptr_){ std::rethrow_exception(excptr_); } return * static_cast< std::string * >( ret); } }; X x; std::cout << x( 7) << std::endl; output: 7
execution_context
class execution_context { public: static execution_context current() noexcept; template< typename Fn, typename ... Args > execution_context( Fn && fn, Args && ... args); template< typename StackAlloc, typename Fn, typename ... Args > execution_context( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Args && ... args); template< typename StackAlloc, typename Fn, typename ... Args > execution_context( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn, Args && ... args); execution_context( execution_context const& other) noexcept; execution_context( execution_context && other) noexcept; execution_context & operator=( execution_context const& other) noexcept; execution_context & operator=( execution_context && other) noexcept; explicit operator bool() const noexcept; bool operator!() const noexcept; void * operator()( void * vp = nullptr); template< typename Fn > void * operator()( exec_ontop_arg_t, Fn && fn, void * vp = nullptr); bool operator==( execution_context const& other) const noexcept; bool operator!=( execution_context const& other) const noexcept; bool operator<( execution_context const& other) const noexcept; bool operator>( execution_context const& other) const noexcept; bool operator<=( execution_context const& other) const noexcept; bool operator>=( execution_context const& other) const noexcept; template< typename charT, class traitsT > friend std::basic_ostream< charT, traitsT > & operator<<( std::basic_ostream< charT, traitsT > & os, execution_context const& other); };
current
()
static execution_context current() noexcept;
Возвращает экземпляр excution_context, указывающий на контекст активного исполнения.
Ничего.
template< typename Fn, typename ... Args > execution_context( Fn && fn, Args && ... args); template< typename StackAlloc, typename Fn, typename ... Args > execution_context( std::allocator_arg_t, StackAlloc salloc, Fn && fn, Args && ... args); template< typename StackAlloc, typename Fn, typename ... Args > execution_context( std::allocator_arg_t, preallocated palloc, StackAlloc salloc, Fn && fn, Args && ... args);
Создает новый контекст выполнения и подготавливает контекст для выполнения fn
. fixedsize_stack
используется в качестве распределителя стека по умолчанию (размер стека == fixedsize_stack::traits::default_size()). Конструктор с типом аргумента , выделенным
, используется для создания пользовательских данных (например, дополнительных структур управления) поверх стека.
execution_context( execution_context const& other) noexcept;
Копии other
, например, базовая структура управления совместно с *this
.
Ничего.
execution_context( execution_context && other) noexcept;
Переносит структуру управления в *this
.
Ничего.
execution_context & operator=( execution_context const& other) noexcept;
Копии Состояние other
to *this
, структура управления является общей.
Ничего.
execution_context & operator=( execution_context && other) noexcept;
Переносит управляющую структуру других
на *это
с помощью семантики перемещения.
Ничего.
operator bool
()
explicit operator bool() const noexcept;
true
, если * это
указывает на структуру управления.
Ничего.
operator!
()
bool operator!() const noexcept;
true
, если * это
не указывает на структуру управления.
Ничего.
operator()
()
void * operator()( void * vp = nullptr) noexcept;
Хранит внутри текущие контекстные данные (указатель стека, указатель команд и регистры процессора) текущего активного контекста и восстанавливает контекстные данные из *this
, что подразумевает переход к *this
. Аргумент void pointer, vp
, передается в текущий контекст для возврата последним вызовом execution_context::оператор()
в той же нити. fn
выполнен с аргументами args
поверх стека this
.
Поведение не определено, если оператор()()
называется, в то время как исполнение_контекст::current() возвращает * это
(например, возобновление уже запущенного контекста). Если функция контекста верхнего уровня возвращается, называется std::exit()
.
Аргумент указателя пустоты перешел к последнему вызову execution_context::operator(), если таковой имеется.
operator(exec_ontop_arg_t)
()
template< typename Fn > void * operator()( exec_ontop_arg_t, Fn && fn, void * vp = nullptr);
Аналогично execution_context::operator(). Кроме того, функция fn
выполнена с аргументами vp
в контексте *this
(например, кадр стека fn
выделен на стеке this
).
Аргумент указателя пустоты перешел к последнему вызову execution_context::operator(), если таковой имеется.
operator==
()
bool operator==( execution_context const& other) const noexcept;
true
, если * это
и другие
представляют собой тот же контекст выполнения, фальсифицированный
в противном случае.
Ничего.
operator!=
()
bool operator!=( execution_context const& other) const noexcept;
! (другой == * это)
Ничего.
operator<
()
bool operator<( execution_context const& other) const noexcept;
true
, если это != прочее
истинно, а заданный реализацией полный порядок execution_context
значений мест это
до прочее
, ложно иначе.
Ничего.
operator>
()
bool operator>( execution_context const& other) const noexcept;
other < this
Ничего.
operator<=
()
bool operator<=( execution_context const& other) const noexcept;
! (other < this
Ничего.
operator>=
()
bool operator>=( execution_context const& other) const noexcept;
! (* this < other
Ничего.
operator<<()
template< typename charT, class traitsT > std::basic_ostream< charT, traitsT > & operator<<( std::basic_ostream< charT, traitsT > & os, execution_context const& other);
Записывает представление other
для потоковой передачи os
.
os
Статья Class execution_context (version 1) раздела Chapter 1. Context Chapter 1. Context может быть полезна для разработчиков на c++ и boost.
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.
:: Главная :: Chapter 1. Context ::
реклама |