Check out System.Threading.ThreadPool.QueueUserWorkItem(). You can create tons of workitems and it will create threads on demand. You can also create threads easily in C#. I'm not sure how it interacts with the UI, but it depends on the GUI library. Usually you have one thread for the gui, and threads for everything else. We need to think about how to let asynchronous agents talk to each other, etc. I have done lots of multithreaded code on .Net on Windows, with different strategies. I presume it works the same on Mono on Linux (other than the GUI, which I will ignore.)
It should start in one process. Moving from one process to multiple processes gives reliability advantages, etc. but it also creates work and has performance costs and our code will be reliable anyway. :-)
I believe that we should use the ThreatPool class and never create a thread for M1. The ThreadPool class has a few holes last time I used it, but it is plenty good. The primary use cases are to queue up a workitem for something to be worked on in the future, or to wait on event, and have a callback fired when that event is signaled. This is all asynchronous, so you need locking, but we should just be able to have a very small number of locks.
In C#, you can lock anything lock(object)
//Only one guy goes in here at a time.
You can even lock a type! Do very simple strategies for now. I will have more advice when you have code. I did asynchronous I/O which is fun, but I don't recommend using that with our threadpool. Our goal is simply to create agents.
Note we might find that in some cases, the connection between the lower-level pieces and the higher level pieces are just function calls! If some low-level code needs help, it may as well call the higher level planning code directly because it isn't going to do anything until that returns. If you cannot continue until you get a result, then you do not want asynchronous!
In other words, what I described above is logically asynchronous because it just appears that only occasionally the higher level code is called, but in fact, it is not asychronous as .Net thinks about it.