Я использую Boost Context 1.67 для создания волокна (fcontext API)
с минимально возможным размером стека в Windows 10.
Вероятно, эта проблема касается не только повышения контекста, но и любого сценария, в котором мы используем поток Windows с минимальным размером стека.
Я столкнулся с проблемами при использовании очень маленьких стеков (до 10 Кб)
через исключения stackoverflow, которые вызваны внутренним
исключение стека разматывания, выданное контекстом повышения, как показано ниже:
При использовании большего стека (> 10 кб) я не сталкиваюсь с какими-либо проблемами.
Для воспроизведения достаточно следующего примера:
#include <memory>
#include <utility>
#include <boost/context/all.hpp>
#define STACK_SIZE 8000
struct my_allocator
{
boost::context::stack_context allocate()
{
void* memory = std::malloc(STACK_SIZE);
return {STACK_SIZE,
static_cast<char*>(memory) +
STACK_SIZE};
}
void deallocate(
boost::context::stack_context& context)
{
std::free(static_cast<char*>(context.sp) -
STACK_SIZE);
}
};
int main(int, char**)
{
boost::context::fiber fiber(
std::allocator_arg, my_allocator{},
[](boost::context::fiber&& sink) mutable {
// ...
return std::move(sink);
});
// Will cause a stack unwind exception and
// reproduces the issue
return 0;
}
Усиление контекста здесь используется только для выполнения переключения контекста с выделенным пользователем стеком, вероятно, проблема вызвана некоторыми ограничениями исключений MSVC C ++, которые, вероятно, требуют определенного минимального размера стека для работы. Так же SetThreadStackGuarantee
Функция WinAPI не оказывает никакого влияния на проблему.
Стек выделяется через malloc, как показано в примере.
Можно ли использовать в Windows стеки меньшего размера, чем 10 КБ, при использовании исключений C ++? Какие обстоятельства могут быть причиной ограничения здесь?
К сожалению, Windows API не предоставляет функцию или константу, возвращающую минимально необходимое пространство стека.
Только на 32-битных Windows исключения (SEH) вызывают записи в стеке.
В Win x64 используется обработка исключений на основе таблиц — записи для обработчиков исключений хранятся в разделе pdata.
Так что обработка исключений на x64 не должна влиять на мин. пространство стека.
Соглашение о вызовах x64 требует некоторого пространства — например, 32 байта «теневого пространства» + пространство для регистров XMM … но для хранения регистров требуется всего несколько байтов.
Я думаю, что мин. пространство стека ограничено «кодом инструментария» (например, файлы cookie стека и т. д.) — возможно, это может контролироваться флагами компилятора.
boost.context выделяет память и использует ее в качестве стека (+ реализует переключение контекста).
boost.fiber использует стек из boost.context и резервирует пространство (размещение нового) для структуры управления в верхней части стека каждого волокна (но это < 1kB).
У вас есть возможность использовать интервальную вложенность, чтобы протестировать минимально необходимое пространство стека вашего приложения.
Других решений пока нет …