So, those videos on metaprogramming turned out to be an amazing resource. I think I have some notion of how this could work. I'm going to try and lay out verbally how I'm going to go about this because, well, I don't have the patience right now to fight with actual syntax. If I express ideas poorly or make fundamental errors in my assumptions of how things work, please, somebody tell me.
First of all, we won't make a class out of this. We're going to make a Module, let's call it Asynchronous_Messaging, because that's what I'm planning on calling it. When it's included (and we want it to be included and not extended), it will add two instance variables to the class, @current_thread_count and @max_thread_count. The main beauty of this class will be the method allow_asynchronous, which will take an array of method names as its arguments.
For each method in the list, it will do the following:
create an alias to the original version of the method and then define a new method with the existing method's name (need to play around with define_method as opposed to just def, but I think that the dynamic nature will require define_method, which is kind of sad for performance reasons). This new version of the method will behave as follows:
If @current_thread_count is equal to @max_thread_count, we return the result of the original function (i.e. we get (slightly slower =/) synchronous performance).
If @current_thread_count is less than @max_thread_count, we increment @current_thread_count and grab the current binding of self. We then spawn a new thread, which creates a lambda (or a Proc.new?, not sure if I want a closure here) that executes the original method using that variable binding and stores the result. We then decrement @current_thread_count and return the result and, for the moment, pray that the thread will just die at the end of the method (and hope that, with nothing else happening after the thread's instruction loop, control will return to the main thread while all this is happening). See problems below if you think I'm taking this lightly.
Because we're checking the number of threads and creating the binding before we start concurrent operation, we shouldn't have to worry about mutex with instance/global variables - so long as we either condemn marking methods that modify @ivars as asynchronous.
Problems:
What if our methods are updating @ivars in a roundabout way (say, a mutator err, "setter" - we're in Ruby now :P - gets called from our asynchronous method, or by methods that are called by methods that are called in our method, or whatever)? I honestly don't know how to fix this. In general, I think that we're a bit screwed, because, so long as we're working with a static binding, I don't think that the actual value in the object will be changed. Just the value in that binding. This is why I just suggest saying "hey, if you're going to update state in any way, don't do it asynchronously".
How are rvalues dealt with here? I don't actually know. If computation in the main thread is halted until we have a suitable assignment in place, then I don't really know what to do here. Going along with this is the control problem I mentioned earlier. I'm going to do a couple of simple experiments to see if I can figure this out in any easy way tonight. In either case, I'll make a post with the results (and the code I used, for peer review).
In any case, I finlly have hope that I may be able to actually get even a poor implementation of what I was hoping for finished in a reasonable length of time. I'm thinking now.
Monday, March 30, 2009
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment