A Plugin architecture in .net and handling Events
I need to write an app that that will iterate over our database, and perform various anaylsis on each record. In order to do this (partially for the learning exercise in creating plugin support) I want to use a Plugin model.
Currently, I have a simple Interface in my main app, which plugins can Implement. My app then loads all DLL's in a folder looking for ones implementing the Interface.
As you can see in the pseudo-code below, I have to keep performing a loop through all loaded plugins calling the process methods.
Sub ProcessData()
For Each Record In MyDataSet
For Each Plugin In MyPluginCollection
Plugin.ProcessRecord(Record)
Next
Next
End Sub
If I wanted each of the plugins to fire asynchronously, how would I track when all the plugins are done?
Sub ProcessData()
For Each Record In MyDataSet
# Start all the plugins off on their processing task
For Each Plugin In MyPluginCollection
CreateNewThreadFor Plugin.StartProcess(Record)
Next
# Do not start the ne开发者_Python百科xt record until this record is completed by all plugins
Dim Complete As Boolean = False
While Not Complete
For Each Plugin In MyPluginCollection
If Plugin.IsBusy Then
Complete = False
End If
Next
DoEvents
End While
Next
End Sub
Or am I just opening myself up for a world of pain trying to multithread it in this way?
An alternative to using manual reset events could be:
ForEach plugin
Create new thread for plugin
Add thread to thread list
Start the plugin method execution
Next
ForEach Thread in thread list
Thread.Join() //blocking call until Thread is completed
With the anonymous and extension methods this can achieved with very few lines. Here's an example in C# (not tested):
List<Thread> lstThreads = new List<Thread>();
Thread objThread;
foreach(Record r in MyDataSet)
{
lstThreads.Clear();
MyPluginCollection.ForEach(delegate(Plugin p)
{
objThread = new Thread(new ThreadStart(delegate()
{
p.StartProcess(Record);
}));
lstThreads.Add(objThread);
});
lstThreads.ForEach(t => t.Start());
lstThreads.ForEach(t => t.Join());
}
Best way would be to extend your Interface with an Event "ProcessCompleted" and checking within that event if every PlugIn is ready (f.e. with a Property "ProcessInProgress").
Bobby
You want to read up on ManualResetEvents. They will do the trick. http://www.codeproject.com/KB/threads/AutoManualResetEvents.aspx
Thats not to say you aren't entering a world of pain, however.
here is an example. paste into a command line app
var r = new Random();
Action a = () => Thread.Sleep(r.Next(5000));
Action<int> process = i => //represents your plugin
{
Console.WriteLine("Thread " + i + " started");
Thread.Sleep(r.Next(5000));
Console.WriteLine("Thread " + i + " finished");
};
var mres = new List<ManualResetEvent>();
for (var i = 0; i < 10; i++)
{
var count = i;
var mre = new ManualResetEvent(false);
new Thread(() =>
{
process(count);
mre.Set();
}).Start();
mres.Add(mre);
}
ManualResetEvent.WaitAll(mres.ToArray()); //try commenting this line
Console.WriteLine("All threads finished. Press enter to continue");
Console.ReadLine();
精彩评论