New Early Access builds

Ron Pressler ron.pressler at oracle.com
Tue Jun 30 22:54:40 UTC 2020


OK, but assigning multiple virtual threads to some single system thread and
having a scheduler that assigns them to the *current* thread are two different
things. While I think the latter is possible (it would be interesting to try),
the former is probably easier. What you can, therefore, do is have your main
thread set up multiple schedulers -- however many you need -- each with a single
worker platform thread, and then have the main thread submit a single virtual
thread to each. Each of those virtual threads will then create and manage other
virtual threads that would share the same carrier as itself. If that's
acceptable, I don't think you need to write your own scheduler -- use
Executors.newSingleThreadExecutor().

— Ron


On 30 June 2020 at 20:25:44, Mark Raynsford (org.openjdk at io7m.com) wrote:

On 2020-06-30T19:49:55 +0100  
Ron Pressler <ron.pressler at oracle.com> wrote:  

> You will need to write a custom Executor, more likely an ExecutorService. You’ll probably   
> want to run the execution loop inside close, and perhaps in invokeAll/Any.  

Ok, sounds good! Just so that I know that I actually do need to write  
one. :)  

>  
> Please let us know how it works out.  
>  
> Could you perhaps explain why this use-case is important to you and why using   
> a simple single-worker executor that is not run on the current thread is unsatisfactory?  

It's a little circuitous, but the basic issue is that I'm working under  
soft-realtime constraints (3D rendering), and I'm working with APIs such  
as Vulkan that demand that I make requests from specific threads.  

Essentially, I have one specific thread that talks to Vulkan, and I  
have to guarantee that, at any given moment, I have data available for  
that thread to turn into rendering commands for Vulkan.  

The typical approach for getting things done under these kinds of  
constraints is to break the application up into subsystems, where each  
subsystem is assigned exactly one dedicated heavyweight/kernel thread  
[0]. For example, I have one subsystem/thread in charge of handling  
user input, one subsystem/thread in charge of handling the actual  
simulation state (physics, etc), one subsystem/thread in charge of  
audio, and one subsystem/thread in charge of rendering. There's no  
sharing of state between subsystems, and any communication happens by  
having subsystems react to events published on an event queue. For  
example, the "simulation" subsystem produces immutable snapshots of  
data at a fixed rate, and the rendering subsystem consumes them from  
the event queue.  

Sharing nothing means that code within a single subsystem doesn't need  
to care about synchronization, data races, etc. However, I often want  
to express the work within a given subsystem as a set of more or less  
cooperative tasks - I just don't want the extra semantic complexity  
of dealing with multi-threaded access to data structures, locking, etc.  

Therefore, the most obvious approach to me seems to be to schedule  
virtual threads directly on the carrier thread assigned to each  
subsystem. That way, I get to break my problems up into cooperating  
tasks, but I don't have to protect the data structures internal to  
the subsystem with synchronization. Without virtual threads, I have to  
build things that look and smell a bit like virtual threads (typically  
some sort of monadic structure), but that tend to be hard to debug and  
have nasty stack traces.  

There are exceptions to this, of course. In some cases - such as  
asynchronous loading of resources from disk, and so on - where I really  
don't care which thread is doing the work. Code that actually has to  
manipulate subsystem internal data structures, however, I'd really  
prefer to keep strictly single-(kernel-)threaded.  

[0] https://en.wikipedia.org/wiki/Entity_component_system  

--  
Mark Raynsford | https://www.io7m.com  



More information about the loom-dev mailing list