Hi,
I would like to add multithreading support in the pet language I'm working on [1]. After reading about Nim's thread model, I'm not sure what is the right way to approach this.
In my program, there are a few things that may not be compatible. The VM and values are all ref objects [2]. The VM is a global object.
If I don't change things dramatically, I was thinking I can do this:
A few questions / issues with this approach:
Not sure whether I'm on the right path. Please shed some light on me. Any comments or suggestions are welcome.
The important question is "how does threading work in your language?". What are the primitives it supports? How can data be shared between threads? Does it only support message passing?
Once you have answered these questions you can think about how your implementation needs to do it. Your implementation based on ref might not survive this and you need to replace ref with ptr and a custom atomic reference counting mechanism. But it should be managable.
Regarding the primitives you support, it's important to know if you want multithreading for IO, multithreading for compute, or both, hence tell us what the multithreading use-cases are and read this (disclaimer, self-promotion) blog post: https://nim-lang.org/blog/2021/02/26/multithreading-flavors.html
In particular, it's unclear if you want to parallelize your VM (why? when?) or offer parallel primitives for programs build on your VM (in that case, you don't need to change anything).
Quite important to know if you want multithreading for IO is how you will handle async?
Also if you want unified handling (say async/await) for async, parallel IO and parallel compute tasks. "Simple" unified handling will have performance implications for compute tasks (due to kernel context switches) but significantly streamline ergonomics and implementation.
If we ignore the std/threadpool module which is being phased out, Nim offers you a blank slate on top of Windows/Unix thread creation/destruction primitives. Only thing you cannot do is preemptive multithreading (as opposed to cooperative) where you pause a thread and run another one without the paused thread cooperation, premptive multithreading can only be done by the OS (well, maybe you can cheat with signals ...).
Thanks a lot for the suggestions.
What I would like to support is what you'll expect from any language with multithread support
I'll see what is possible with my current design first, and then see if I need to change some part of my design in order to provide better multithread support.
@mratsim will read thru your blog. thanks for the pointer.
Re-reading your post and here are some of my answers:
I would like to add multithread primitives to allow users to hand some tasks to threads. It should support both IO and Compute tasks. The goal is to better utilize multi-cores.
So either spawn or thread creation or both are ok.
Parallelizing the VM is not currently a goal.
Regarding premptive vs non-preemptive, whatever Nim supports is what you get since the language is built in Nim.