Bug 12090 – Make std.concurrency compatible with fibers as threads
Status
RESOLVED
Resolution
FIXED
Severity
enhancement
Priority
P2
Component
phobos
Product
D
Version
D2
Platform
All
OS
All
Creation time
2014-02-06T10:35:00Z
Last change time
2015-09-07T17:46:08Z
Assigned to
nobody
Creator
sean
Comments
Comment #0 by sean — 2014-02-06T10:35:13Z
In order to scale std.concurrency past a small number of threads, some support must be added for spawning fibers. Also, std.concurrency should be made compatible with third-party libraries, like vibe.d, that use fibers as a core facet of their design.
I had been delaying this project because I felt that any changes to what is considered a "thread" should support the default thread-local storage model implicitly. However, this was based on the idea that any change would be to the implementation only, and so the user would not necessarily have any indication that they'd spawned a fiber instead of a kernel thread.
Upon further reflection, I think this approach is not the correct one, and as per the design of Druntime, the user should be given the choice of how multiprocessing will occur. Then the choice to use fibers instead of threads, for example, can be made by the user at design time with the knowledge that their code doesn't use thread-local statics in an incompatible manner. This serves to decouple the thread-local storage issue from multiprocessing in general and lets us move forward on std.concurrency without being blocked by a technical obstacle in Druntime.
So std.concurrency should be adapted so that the multiprocessing model can be configured, at process startup, by plugging in a Scheduler which handles the details of spawning threads, yielding instead of blocking on a wait when a message queue is empty, and so on. By default, if no Scheduler is supplied, std.concurrency should work just as it always has. This will save any memory allocations or performance penalties in the typical case. Also, the design should be such that any allocations are minimized as much as possible.
Comment #1 by sean — 2014-02-06T10:46:39Z
I think something like the following will work:
interface Scheduler
{
void start(void delegate() op);
void spawn(void delegate() op);
void yield();
@property ref ThreadInfo thisInfo();
Condition newCondition(Mutex m);
}
When using a scheduler, main() should do any initial setup that it wants and then call scheduler.start(), which will effectively spawn the supplied delegate as a thread and then begin dispatching.
The remaining functions are all used by the std.concurrency implementation. spawn() does the work of actually creating new threads, yield() will yield execution of the current fiber (or optionally, thread) so that multiprocessing can occur, and newCondition constructs a Condition object used by send() and receive() to indicate that a message has arrived, block waiting for a new message, etc. Finally, ThreadInfo is needed so that the thread-local statics currently in std.concurrency can be made local to the "thread" currently executing. If thisInfo is called by a thread or fiber not spawned by std.concurrency, it can return a thread-local copy instead.
Comment #2 by jakobovrum — 2014-02-09T07:15:04Z
(In reply to comment #1)
> I think something like the following will work:
>
> interface Scheduler
> {
> void start(void delegate() op);
> void spawn(void delegate() op);
> void yield();
> @property ref ThreadInfo thisInfo();
> Condition newCondition(Mutex m);
> }
>
>
> When using a scheduler, main() should do any initial setup that it wants and
> then call scheduler.start(), which will effectively spawn the supplied delegate
> as a thread and then begin dispatching.
>
> The remaining functions are all used by the std.concurrency implementation.
> spawn() does the work of actually creating new threads, yield() will yield
> execution of the current fiber (or optionally, thread) so that multiprocessing
> can occur, and newCondition constructs a Condition object used by send() and
> receive() to indicate that a message has arrived, block waiting for a new
> message, etc. Finally, ThreadInfo is needed so that the thread-local statics
> currently in std.concurrency can be made local to the "thread" currently
> executing. If thisInfo is called by a thread or fiber not spawned by
> std.concurrency, it can return a thread-local copy instead.
It has been suggested that std.concurrency should also be able to support IPC (most importantly by Andrei in the module's documentation). The proposed Scheduler interface seems close to supporting that for fork()-based code (which of course isn't an option for non-POSIX systems), but do you have any thoughts on this?
Comment #3 by yebblies — 2014-02-11T03:36:03Z
(In reply to comment #2)
>
> It has been suggested that std.concurrency should also be able to support IPC
> (most importantly by Andrei in the module's documentation). The proposed
> Scheduler interface seems close to supporting that for fork()-based code (which
> of course isn't an option for non-POSIX systems), but do you have any thoughts
> on this?
IPC depends on serialization, which we don't have yet in phobos.
Comment #4 by jakobovrum — 2014-02-13T07:45:00Z
(In reply to comment #3)
> (In reply to comment #2)
> >
> > It has been suggested that std.concurrency should also be able to support IPC
> > (most importantly by Andrei in the module's documentation). The proposed
> > Scheduler interface seems close to supporting that for fork()-based code (which
> > of course isn't an option for non-POSIX systems), but do you have any thoughts
> > on this?
>
> IPC depends on serialization, which we don't have yet in phobos.
Well, the fact remains that the Scheduler interface may not be forward compatible with IPC. I think it's worth pointing out.
Comment #5 by eco — 2014-04-27T22:09:25Z
The pull request looks nice. How hard do you think it'd be to add an M:N scheduler to the mix?
Comment #6 by sean — 2014-05-01T18:20:50Z
Not hard. The existing schedules should serve as a decent basis for the work.
Comment #10 by pro.mathias.lang — 2015-09-07T17:46:08Z
This was fixed in 2.067 but since the title of the P.R. didn't include "Fix", bugzilla didn't pick it up.
Note: It's not showing up in the changelog as a result.