Windows: Throwing Exceptions from Fibers in D2.059: Access Violation

Andrew Lauritzen andrew.lauritzen at gmail.com
Fri Apr 20 10:21:28 PDT 2012


> To be precise, fibers in and of themselves aren't exacty what I 
> want, but are the best means to getting it that I've seen so 
> far. They enable efficient implementation of coroutines, which 
> many languages either cannot express at all, or can only 
> express very poorly by using the sledgehammer of a full-on 
> kernel thread to get it. A call stack is a very useful way to 
> group logic, and being forced to go outside the language and 
> ask the OS for another one is a shame.
>
> Game logic is an area where this technique REALLY shines. Case 
> in point: Unity3D. The entire engine is built around C#'s 
> iterator method facility to implement coroutines to control 
> entity logic. Hundreds or even thousands of them can be active 
> with very little overhead compared to a full thread context 
> switch. Unfortunately, they're hamstrung by not being a true 
> coroutine (you can only yield from the top frame).
>
Right, exactly the above! Fibers are totally uninteresting as a 
"lighter thread" or unit of scheduling for the reasons that you 
note, but coroutines are just a better way to write a lot of 
code. This is basically the entire premise for the Go programming 
language, so it's worth taking a peek at that if you haven't 
already.

In my example, it's effectively to yield and restore 
connection-specific state for different clients. In the 
equivalent C code, it's a gigantic mess of a state machine 
specified by big switch statements and is almost impossible to 
follow the intended flow. With coroutines it's quite simple: you 
write the code in the most natural way - as if your sockets were 
blocking - and when you would otherwise block, you yield the 
fiber instead and come back to it when more socket data is 
available. Go takes this a step further by embedding the yields 
(and more) into both the standard library and the language 
itself. It's quite a powerful programming model for certain types 
of work.

When I started running into fiber issues I tried to use threads 
instead (just to avoid the issues; I have no need of the 
parallelism or other utilities that they provide in this 
application) but I ran into a bunch of problems.

First, D's insistence on message-passing, while noble and 
respectable, is not a perfect fit  for cases where I have no need 
or desire to synchronize large portions of the data structures. 
In general, this sort of coarse-grained opportunistic parallelism 
extracts very few additional useful cycles out of multicore 
hardware compared to a more targeted fine-grained approach. As 
you note, there's a reason that a lot of the scheduling is 
starting to move more to user-space "tasks".

(As an aside, it would be awesome to see a Cilk-like work 
stealing implementation in D. That's by far the easiest first 
step to really extracting parallelism our of programs and you can 
often get most of the benefit just with that. It's yet another 
elegant way to use the call-stack for expressing and exploiting 
parallelism and dependencies.)

Second, and more importantly, there didn't seem to be a clean way 
to wait on multiple things in D right now. For instance, I want 
to yield a thread/fiber until there is either a socket state 
change, *or* a thread message. This can be a minor problem with 
fibers, but less-so since the fiber itself can basically just 
take over whatever work needs to be done rather than trying to 
wake other threads. There doesn't seem to be a clean way to do 
this in D currently other than waking threads and basically 
polling multiple things, which I'm sure you can agree is not 
ideal.

> Stack overflow?  Give the fiber a larger stack when you create 
> it. The default is really rather small.

I'm fairly certain that it's not a "real" stack overflow... the 
program continues to operate normally unless the debugger is 
stepping through and it only happens when an exception is thrown. 
And it happens pretty much always when an exception is thrown, 
you just won't see it unless you have a debugger attached to see 
the output. So like I said, it is somewhat worrisome, but the 
program seems to be running properly despite it, so it may be a 
red herring.


More information about the Digitalmars-d mailing list