WindowsのFiberでcoroutineを作れないかと思ったものの、案の定、失敗。
動かないソースだけ貼り付けとく。
#include <windows.h> #include "ruby.h" static VALUE Fiber; static VALUE FiberError; struct win32fiber { LPVOID main_fiber; LPVOID fiber; VALUE proc; }; static void rb_win32fiber_mark(struct win32fiber *p) { if (!NIL_P(p->proc)) { rb_gc_mark(p->proc); } xfree(p); } static void rb_win32fiber_free(struct win32fiber *p) { if (p->fiber) { DeleteFiber(p->fiber); } xfree(p); } static VALUE rb_win32fiber_alloc(VALUE klass) { struct win32fiber *p; p = ALLOC(struct win32fiber); p->main_fiber = NULL; p->fiber = NULL; p->proc = Qnil; return Data_Wrap_Struct(klass, rb_win32fiber_mark, rb_win32fiber_free, p); } static VALUE corutine_proc_call(VALUE proc) { return rb_funcall(proc, rb_intern("call"), 0); } static VALUE corutine_yield(VALUE data1, VALUE data2, VALUE self) { struct win32fiber *p = (struct win32fiber *) data2; SwitchToFiber(p->main_fiber); return Qnil; } static void _stdcall corutine(LPVOID param) { struct win32fiber *p = (struct win32fiber *) param; rb_iterate(corutine_proc_call, p->proc, corutine_yield, (VALUE) p); } static VALUE rb_win32fiber_initialize(VALUE self) { struct win32fiber *p; rb_need_block(); Data_Get_Struct(self, struct win32fiber, p); p->main_fiber = ConvertThreadToFiber(NULL); if (p->main_fiber == NULL) { rb_raise(FiberError, "ConvertThreadToFiber failed: %d", GetLastError()); } p->fiber = CreateFiber(0, corutine, (LPVOID) p); if (p->fiber == NULL) { rb_raise(FiberError, "CreateFiber failed: %d", GetLastError()); } p->proc = rb_block_proc(); return Qnil; } static VALUE rb_win32fiber_resume(VALUE self) { struct win32fiber *p; Data_Get_Struct(self, struct win32fiber, p); SwitchToFiber(p->fiber); return Qnil; } __declspec(dllexport) void Init_win32fiber() { Fiber = rb_define_class("Fiber", rb_cObject); FiberError = rb_define_class_under(Fiber, "Error", rb_eStandardError); rb_define_alloc_func(Fiber, rb_win32fiber_alloc); rb_define_private_method(Fiber, "initialize", rb_win32fiber_initialize, 0); rb_define_method(Fiber, "resume", rb_win32fiber_resume, 0); }
require 'win32fiber' fiber = Fiber.new do loop do puts "春" yield puts "夏" yield puts "秋" yield puts "冬" yield end end loop do while gets fiber.resume end end