Multithreading and the Singleton Pattern
In December of last year, as part of my undergraduate thesis, I developed a piece of software that statistically extrapolated electrical network data. This software required a lot of simulations - I needed a year’s worth of data at 15 minute intervals.
Doing the math:
365 days ✕ 24 hours ✕ 4 measurements/hour = 35040
Each simulation took 2.5 seconds to run, and so those 35040 simulations were going to take just over a day to run.
I was at a stage about a week out from the end of the project, and a spare day just to run simulations wasn’t really viable.
So, I did what any programmer would do - I tried to parallelise my application.
The simulator I was using, however, wasn’t particularly keen on the idea - turns out, the API implements a singleton pattern. Just for the record - it was not an appropriate choice in this situation (I’m not really sure it’s ever a great choice actually).
If I was going to parallelise this application, I was going to have to multi-process it.
Inter-process Communication
The basic procedure is:
- Spawn a child process (in this case, the simulator)
- Connect some anonymous pipes between the child and parent processes
- Use stream-based I/O for communication between processes.
That’s fine, but it’s a lot of boilerplate code - what if there was a way to automate it?
Aspect-Oriented Programming with PostSharp
PostSharp is a great developer tool, based on the idea of applying attributes to .NET code that somehow modify the behaviour of the attribute target. I wondered if it was possible to write a ‘RunOutOfProcessAttribute’ that could just be slapped on top of a class to force it to run in another process?
Turns out it is: PostSharp has an aspect (MethodInterceptionAspect
) that pulls the method body out of a method, replaces it with your custom code, and then allows you to call the method body later.
For our purposes, what we need to do in that custom code is:
- Test to see if this code is running in-process or out-of-process
- If it’s running in-process, forward the call to our external process
- If it’s running out-of-process, run the code, and forward the result back to the calling process.
Use Procedure
The basic use procedure is:
- Add a new Exe project to your solution.
- Add classes to the Exe.
- For each class that you want to run out-of-process:
- Mark the class with the
[RunOutOfProcess]
attribute. - Make sure the class implements
IDisposable
. - Make sure that no initialisation logic is in the constructor - instead, just put in a call to an
Init()
function with the same parameters as the constructor. (this is a workaround for a PostSharp quirk) - Mark your
Init()
function with the[Initializer]
attribute. - In the Exe entry point, simply add a call to
IPCTK
, where.OutOfProcessHandler .Loop( arg0, arg1); arg0
andarg1
are the first and second command-line parameters respectively.
Then, just add a reference to your new Exe project and start using the classes. Any classes marked with [RunOutOfProcess]
will be… erm, Run Out Of Process.
A Couple of Useful Bits and Pieces
Attribute Targeting
MethodInterceptionAspect
s apply only to methods, not to classes. To ensure that we can put [RunOutOfProcess]
on classes and obtain the desired behaviour, we define the RunOutOfProcessAttribute
as follows:
[Serializable] //Required by PostSharp
//target all methods of class...
[MulticastAttributeUsage(MulticastTargets.Method)]
//...but only allow the attribute to be applied to the class
[AttributeUsage(AttributeTargets.Class)]
public sealed class RunOutOfProcessAttribute : MethodInterceptionAspect
We then add the following CompileTimeValidate hook, which silently ignores private/protected member functions:
//Applies the attribute only to:
// classes implementing IDisposable,
// only on public methods,
// or on methods marked with [Initializer]
public override bool CompileTimeValidate(MethodBase method)
{
if (method.DeclaringType.GetInterface("IDisposable") == null)
throw new InvalidAnnotationException(
"Class must implement IDisposable " + method.DeclaringType);
if (!method.Attributes.HasFlag(MethodAttributes.Public) // not public
&& !MethodMarkedWith(method,typeof(InitializerAttribute))) //not constructor
return false; //silently ignore.
return true;
}
Serialisation
IPCTK works by serialising/deserialising the arguments to and return values from methods and sending these along anonymous pipes. As such:
- The toolkit is most useful when the ratio of expected compute time to input/output size is high.
- If anything needed to be optimised ever, it was serialisation for this purpose.
NetSerialiser would probably offer a good performance improvement, at the expense of being unable to serialise implementers of ISerializable
. Maybe I’ll look into this in a future version.
More Info
For more information, take a look at the IPCTK project page on github.