Я делаю облегченные кооперативные потоки для виртуальной машины C ++, и хотя потоки работают просто отлично, стоит отложить вызов std :: function:
template <typename T, typename... Args>
inline Thread* create(const T& func, Args&&... args)
{
...
auto* thread = new (xxx) Thread(
[func, args...] () {
self()->exit( func(args...) );
});
Приведенная выше функция будет хранить std :: function с аргументами в другой std :: function, которая позволяет отложить вызов до завершения системного вызова клона, и мы запускаем (среди прочего) новый стек.
Затем функция просто вызывается так, как если бы она была функцией запуска потока, и ее память освобождается после ее возвращения или выхода из потока.
API подобен обычным потокам C ++: вы передаете функцию, а затем аргументы. Есть ли способ сделать отсроченный звонок дешевле? Какие варианты есть? Я использую все последние компиляторы (Clang-11, G CC -9.1) с включенным C ++ 17.
Код доступен здесь: https://github.com/fwsGonzo/libriscv/blob/master/binaries/barebones/libc/microthread.hpp#L95
Я думаю, что должна быть полная копия аргументов. Когда вы создаете новый поток и немедленно вызываете его, параметры все еще доступны, потому что родительский поток все еще там ожидает. Тем не менее, можно go вернуться к основному потоку и оставить функцию, которая делает параметры go вне области действия, в то время как новый поток получен. Не уверен, как решить эту проблему, кроме как скопировать / переместить аргументы.
Давайте сравним микропотоки с Lua сопрограммами. Без аргументов:
libriscv: micro threads => median 529ns lowest: 518ns highest: 586ns
lua5.3: coroutines => median 687ns lowest: 667ns highest: 727ns
С аргументами:
libriscv: micro thread args => median 2261ns lowest: 2181ns highest: 2725ns
lua5.3: coroutine args => median 762ns lowest: 735ns highest: 1051ns
Захват по ссылке:
libriscv: micro thread args => median 643ns lowest: 612ns highest: 1319ns
lua5.3: coroutine args => median 748ns lowest: 718ns highest: 842ns
Передача аргументов в микропоток приводит к выделению кучи и полностью разрушает производительность против Lua сопрограмм. Теперь распределения в libriscv не такие медленные, но их нельзя превзойти, просто вставив в стек.