Все реализации сопрограмм, с которыми я сталкивался, используют соберите или проверьте содержимое jmp_buf
. Проблема в том, что он по своей сути не кроссплатформенный.
Я думаю, что следующая реализация не переходит в неопределенное поведение и не полагается на детали реализации. Но я никогда не встречал сопрограмм, написанных таким образом.
Есть ли какая-то внутренняя ошибка в использовании длинного прыжка с потоками?
Есть ли какие-то скрытые ошибки в этом коде?
#include <setjmp.h>
#include <thread>
class Coroutine
{
public:
Coroutine( void ) :
m_done( false ),
m_thread( [&](){ this->start(); } )
{ }
~Coroutine( void )
{
std::lock_guard<std::mutex> lock( m_mutex );
m_done = true;
m_condition.notify_one();
m_thread.join();
}
void start( void )
{
if( setjmp( m_resume ) == 0 )
{
std::unique_lock<std::mutex> lock( m_mutex );
m_condition.wait( lock, [&](){ return m_done; } );
}
else
{
routine();
longjmp( m_yield, 1 );
}
}
void resume( void )
{
if( setjmp( m_yield ) == 0 )
{
longjmp( m_resume, 1 );
}
}
void yield( void )
{
if( setjmp( m_resume ) == 0 )
{
longjmp( m_yield, 1 );
}
}
private:
virtual void routine( void ) = 0;
jmp_buf m_resume;
jmp_buf m_yield;
bool m_done;
std::mutex m_mutex;
std::condition_variable m_condition;
std::thread m_thread;
};