----- Original Message ----- From: "Igor Stasenko" siguctua@gmail.com To: "The general-purpose Squeak developers list" squeak-dev@lists.squeakfoundation.org Sent: Monday, October 29, 2007 7:59 PM Subject: Re: Concurrent Futures
On 30/10/2007, Rob Withers reefedjib@yahoo.com wrote:
----- Original Message ----- From: "Igor Stasenko" siguctua@gmail.com To: "The general-purpose Squeak developers list" squeak-dev@lists.squeakfoundation.org Sent: Monday, October 29, 2007 5:59 PM Subject: Re: Concurrent Futures
On 30/10/2007, Rob Withers reefedjib@yahoo.com wrote:
I'd like to hear some description if the concept you have in mind, if you have the time. What are you thinking about in this arena?
Well, in my concept i don't have a vats. A computing resources(native threads) managed by VM and not visible at language level. So, a VM parallelism is not a language parallelism. You can't predict what native thread will serve concrete message for concrete object, thus a load is distributed evenly. This haves own limitations, but mostly when you interacting with external libraries through primitives - some of the libraries can not work (or can work differently) when you accessing them from different native threads. Some of the libraries designed with no multithreading in mind, so using them concurrently may cause a system crash. But i don't think that i'm alone with this problem. We need to find some good ways how to control that all calls to some external library must be invoked only from a single thread of execution, while for other libraries its ok to call them from anywhere.
How do you protect against simultaneous accesses to memory for writes/reads?
I have described this previously.
I must have missed it.
The idea is simple. Since we have limited set of write operations in object memory we could design a system which prevents a primitive operations (such as primat: put:) from running concurrently on the same object. This means (like in your concept), that each object should have an additional slot identifying a context where it used as receiver. The only write operations which could modify object memory within any method body is write to receiver memory (like setting ivar or indexed var). Other operations (like pushing on stack) is safe, because we'll have separate stack for each execution thread. The message evaluation sequence then can be done as following:
- check receiver's assigned context
- if it's nil, then assign it to current and start executing method
- if its not nil, then schedule method execution to the thread, which
owns given context.
It seems to me that you are building event-loops in the VM. Consider anObject that is sent a msg on thread 1, so he is assigned to thread 1 and you start processing it with thread 1. In the meantime, 3 msgs are sent to this object on threads 2, 3, and 4. Each message send is scheduled for processing by thread 1, when it becomes available. There is your event-loop.
The difference is that you allow objects to be reassigned based on thread availability. Since we have a shared memory, that is as simple as setting the new context. This is similar to ideas I had for redistributing objects to different Vats based upon msg send density, which could be monitored, or user specification.
when performing a message send in method we deactivate the context, which means that we can set assigned object's context to nil, and set it again when activate context again. Or if we not, then all message sends to given object will be scheduled to same native thread. I don't know what is best - both approaches having own pros and cos. Retaining a context can help us with making all calls to some external library be invoked from single thread.
Indeed. That would be a Vat.
Either way we should ensure that there's a single active context at some point of time in system running using same receiver. Also, we can leave most primitives unmodified and be careless about concurrency in these primitives, because by design, there can be only single primitive running in system for particular object at any point of time.
But the primitive may have internal state that can't be shared.
If you can see, such approach gives not much in solving concurrency issues at language side. But that's where i think developers should choose the way. We can provide all what they need (semaphores/promises/futures e.t.c.) in libraries and provide some additional primitives for controlling new aspects of VM.
I could certainly build the language features I am interested in on top of such a VM.
cheers, Rob