为什么以下代码在Windows 10下崩溃?它会在yield()
来电中setjmp()
停留。我违反了哪些规则?我想我永远不会从调用setjmp()
的函数返回。该代码在linux / amd64下完美运行。
class coroutine
{
jmp_buf env_in_;
jmp_buf env_out_;
::std::function<void()> f_;
bool running_;
bool terminated_;
::std::unique_ptr<char[]> stack_;
char* const stack_top_;
public:
explicit coroutine(::std::size_t const N = 128 * 1024) :
running_{false},
terminated_{true},
stack_(new char[N]),
stack_top_(stack_.get() + N)
{
}
template <typename F>
explicit coroutine(::std::size_t const N, F&& f) :
coroutine(N)
{
assign(::std::forward<F>(f));
}
auto terminated() const noexcept
{
return terminated_;
}
template <typename F>
void assign(F&& f)
{
running_ = terminated_ = false;
f_ = [this, f = ::std::forward<F>(f)]() mutable
{
// stack switch
#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
asm volatile(
"movq %%rsp, %0"
:
: "rm" (stack_top_)
: "rsp"
);
#elif defined(i386) || defined(__i386) || defined(__i386__)
asm volatile(
"movl %%esp, %0"
:
: "rm" (stack_top_)
: "esp"
);
#else
#error "can't switch stack frame"
#endif
f(*this);
running_ = false;
terminated_ = true;
yield();
};
}
void yield() noexcept
{
if (setjmp(env_out_))
{
return;
}
else
{
longjmp(env_in_, 1);
}
}
void resume() noexcept
{
if (setjmp(env_in_))
{
return;
}
else if (running_)
{
longjmp(env_out_, 1);
}
else
{
running_ = true;
f_();
}
}
};
以下是测试程序:
#include <iostream>
#include "coroutine.hpp"
struct A
{
~A()
{
::std::cout << "destroyed" << ::std::endl;
}
};
int main()
{
coroutine c(1024 * 1024);
c.assign([](coroutine& c)
{
A a;
for (int i{}; i != 3; ++i)
{
::std::cout << i << ::std::endl;
c.yield();
}
}
);
while (!c.terminated())
{
c.resume();
}
return 0;
}