Skip to main content
GameDev.net gamedev.net
🔒 Locked

C++ coroutines

Started by antareus Jun 22, 2004 at 10:10 PM 5 replies 4.7k views
Original Post
antareus
antareus
I don't know how, but I ended up on this article, which discusses a simple Coroutine implementation in .NET using the Fibers API. Has anyone used it? A quick Google Groups search shows it is great for coroutines, I was wondering if anyone had gone forward with it. I am very interested in anything that has the potential to turn an asynchronous control flow into a linear one without the burdens that threads bring. Because fibers are made to be scheduled by the application, you can potentially avoid a host of race conditions. I sketched a Fiber class out:

#ifndef FIBER_HPP
#define FIBER_HPP

#define _WIN32_WINNT 0x0400

#include <cassert>
#include <windows.h>

#define yield { if(GetFiberData()) reinterpret_cast<Win32::Fiber*>(GetFiberData)->Pause(); }

namespace Win32
{
	enum FiberState
	{
		FiberCreated,
		FiberRunning,
		FiberStopping,
		FiberStopped
	};

	class Fiber
	{
	public:
		explicit Fiber(void (* fiberProc)(void*), void* arg = 0) :
			ParentHandle(0),
			FiberProc(fiberProc),
			Argument(arg),
			State(FiberCreated)
		{
			Handle = CreateFiber(0, Fiber::FiberBounceProc, reinterpret_cast<void*>(this));
		}

		void* GetParentHandle() const
		{
			return ParentHandle;
		}

		void Pause()
		{
			if(GetCurrentFiber() == Handle)
			{
				SwitchToFiber(ParentHandle);
			}
		}

		void Run()
		{
			if(ParentHandle == 0)
				ParentHandle = GetCurrentFiber();

			SwitchToFiber(Handle);
		}

	private:
		static void WINAPI FiberBounceProc(void* arg)
		{
			Fiber* fiber = reinterpret_cast<Fiber*>(arg);
			fiber->State = FiberRunning;

			try
			{
				fiber->FiberProc(fiber->Argument);
			}
			catch(...)
			{
				DebugBreak();
			}

			fiber->State = FiberStopping;
			DeleteFiber(fiber->Handle);
			fiber->State = FiberStopped;
		}

	private:
		void*		Handle;
		void*		ParentHandle;
		void		(*FiberProc)(void*);
		void*		Argument;
		FiberState	State;

	};

}
It isn't wonderful and certainly isn't tested, I just needed to get something down. The most glaring problem is easily that of object lifetime issues. Anyway, let me know what you think and what sort of experience you have with fibers.
--God has paid us the intolerable compliment of loving us, in the deepest, most tragic, most inexorable sense.- C.S. Lewis
Zipster
Zipster
Looks fine to me. The only thing you have to remember is that fibers can only schedule other fibers, so you have to first convert the running thread into a fiber before scheduling your first fiber. I'm not sure if this literally converts the thread into a fiber, or simply creates an initial fiber that takes on the identity of the thread.
antareus
antareus
Wow, Greg really seems to hate them. I was seeing if coroutines had the potential to make network parsing any easier, but I couldn't really think of anything offhand that would be significantly easier -- I already buffer up data until I get a full packet, at which point I can parse it pretty easily. I guess they would just help with trimming the amount of state one has to keep.

It is either that, or that I am locked in the asynchronous mindset.
--God has paid us the intolerable compliment of loving us, in the deepest, most tragic, most inexorable sense.- C.S. Lewis
doynax
doynax
here's an interesting link on the subject: clicky
could be useful, if you don't have a problem with macro abuse..
Zipster
Zipster
Quote:
It is either that, or that I am locked in the asynchronous mindset.

The only different between fibers and threads that I see is that the former is more lightweight, and exclusively user-scheduled. So you would use a fiber in a lot of places where you would use a thread, when you want exact control over scheduling. For example, the article gave a simple iterator example over a tree. This would be an annoyance to implement with threads, because since you don't have control over scheduling you'd have to mutex the hell out of it. However, it would be a lot easier with fibers, and would save the hastle of having to somehow maintain state information across calls if you aren't using threads or fibers. Not hard, but as every computer science student would attest to, extremely annoying :)

I'm primarily interested in working with calls that block (like network calls), so fibers wouldn't help by themselves. I'd still have to go with good 'ol threads.

[Edited by - Zipster on June 24, 2004 9:16:10 PM]
RenderTarget
RenderTarget
Quote:
Original post by doynax
here's an interesting link on the subject: clicky
could be useful, if you don't have a problem with macro abuse..


I love macro abuse. I'm firmly in the camp that says if macros expose the algorithm more clearly or simplify potentially buggy program maintenance, go for it.
[sub]My spoon is too big.[/sub]

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.