multithreading - C# 2.0 Multi-threading with a plug-in architecture -
i have established console application in c# 2.0 uses plugin architecture. of right now, program uses basic multi-threading can run several instances. threads created , continue on until application stopped.
each instance can load own variety of plugins , configured separately. plugins inherited base plugin. system has been working charm years. plugins event driven, read various events see if called upon, if not return , let next plugin read events see if called out fire.
this system has been working years. however, further scope of multi-threading allow plugins listen events in asynchronous fashion rather synchronous. 1 of drawbacks of setup once plugin fires , work, locks out instance. when next event fired has wait previous work completed. allow next process take place.
what do, execute plugin , not have wait process end before moving on next process begin event.
i stuck .net 2.0 time being, , must find solution in framework. have looked @ numerous examples , can not find 1 meets criteria. 1 of problems each plugin has own time may take process, , there no way count track percentage plugin complete. plugins start , ends process when done. depending on parameters of event, , plugin can take range of time complete.
my question best way handle multi-threading in situation plugins executed events. have looked @ pages such http://msdn.microsoft.com/en-us/library/2e08f6yc(v=vs.80).aspx , can figure out able have entry point in event driven plugin architecture.
if has clue, appreciate it. lack of multi-threading in manner has been achilles' heel application years.
plugin base: these contain functions triggered events:
using system; using vhabot.communication; namespace vhabot { /// <summary> /// plugin baseclass, must inherited plugins /// </summary> public abstract class pluginbase : marshalbyrefobject { private bool _locked; private string _name; private string _internalname; private int _version; private string _author; private string[] _contributors; private string _description; private pluginstate _defaultstate; private string[] _dependencies; private command[] _commands; /// <summary> /// friendly display name of plugin /// </summary> /// <example> /// <code> /// this.name = "message of day"; /// </code> /// </example> public string name { set { if (_locked) { throw new exception(); } _name = value; } { return _name; } } /// <summary> /// internal name of plugin /// </summary> /// <example> /// <code> /// this.internalname = "vhmotd"; /// </code> /// </example> public string internalname { set { if (_locked) { throw new exception(); } _internalname = value.tolower(); } { return _internalname; } } /// <summary> /// pluigin version /// </summary> /// <remarks> /// versions stored integers only. version 1.0.0 have value of 100 /// </remarks> /// <example> /// <code> /// this.version = 100; /// </code> /// </example> public int version { set { if (_locked) { throw new exception(); } _version = value; } { return _version; } } /// <summary> /// author of plugin /// </summary> /// <example> /// <code> /// this.author = "vhab"; /// </code> /// </example> public string author { set { if (_locked) { throw new exception(); } _author = value; } { return _author; } } /// <summary> /// list of contributors development of plugin. /// </summary> /// <example> /// <code> /// this.contributors = new string[] { "iriche", "kilmanagh" }; /// </code> /// </example> public string[] contributors { set { if (_locked) { throw new exception(); } _contributors = value; } { if (_contributors != null) { return _contributors; } return new string[0]; } } /// <summary> /// description of plugin /// </summary> /// <example> /// <code> /// this.description = "provides interface user view online and/or on private channel."; /// </code> /// </example> public string description { set { if (_locked) { throw new exception(); } _description = value; } { return _description; } } /// <summary> /// default <see cref="vhabot.pluginstate" /> of plugin /// </summary> /// <example> /// <code> /// this.defaultstate = pluginstate.installed; /// </code> /// </example> /// <seealso cref="vhabot.pluginstate" /> public pluginstate defaultstate { set { if (_locked) { throw new exception(); } _defaultstate = value; } { return _defaultstate; } } /// <summary> /// list of other plugins plugin dependent on function /// </summary> /// <remarks> /// plugins referred using internal names. see <see cref="vhabot.pluginbase.internalname" /> /// </remarks> /// <example> /// <code> /// this.dependencies = new string[] { "vhitems" }; /// </code> /// </example> public string[] dependencies { set { if (_locked) { throw new exception(); } _dependencies = value; } { if (_dependencies != null) { return _dependencies; } return new string[0]; } } public command[] commands { set { if (_locked) { throw new exception(); } _commands = value; } { if (_commands != null) { return _commands; } return new command[0]; } } internal void init() { _locked = true; } /// <summary> /// plugin has loaded in response <see cref="vhabot.shellmodules.plugins.load" /> /// </summary> /// <param name="bot"></param> /// /// /// <remarks>code inside method executed when plugin loading</remarks> public virtual void onload(botshell bot) { } /// <summary> /// plugin has unloaded in response <see cref="vhabot.shellmodules.plugins.unload" /> /// </summary> /// <param name="bot"></param> /// <remarks>code inside method executed when plugin unloading</remarks> public virtual void onunload(botshell bot) { } /// <summary> /// plugin has installed in response <see cref="vhabot.shellmodules.plugins.install" /> /// </summary> /// <param name="bot"></param> public virtual void oninstall(botshell bot) { } /// <summary> /// plugin been uninstalled in response <see cref="vhabot.shellmodules.plugins.uninstall" /> /// </summary> /// <param name="bot"></param> public virtual void onuninstall(botshell bot) { } /// <summary> /// plugin has been upgraded (unused) /// </summary> /// <param name="bot"></param> /// <param name="version"></param> /// <remarks>this function not active</remarks> public virtual void onupgrade(botshell bot, int32 version) { } /// <summary> /// response command /// </summary> /// <param name="bot"></param> /// <param name="e"></param> public virtual void oncommand(botshell bot, commandargs e) { } /// <summary> /// response unauthorized command /// </summary> /// <param name="bot"></param> /// <param name="e"></param> public virtual void onunauthorizedcommand(botshell bot, commandargs e) { } /// <summary> /// response command query <see cref="vhabot.shellmodules.commands.gethelp." /> /// </summary> /// <param name="bot"></param> /// <param name="command"></param> /// <returns></returns> /// <remarks>code inside method executed when requested</remarks> public virtual string onhelp(botshell bot, string command) { return null; } /// <summary> /// response custom configuration /// </summary> /// <param name="bot"></param> /// <param name="key"></param> /// <returns></returns> public virtual string oncustomconfiguration(botshell bot, string key) { return null; } /// <summary> /// response plugin message /// </summary> /// <param name="bot"></param> /// <param name="message"></param> public virtual void onpluginmessage(botshell bot, pluginmessage message) { } /// <summary> /// response bot message /// </summary> /// <param name="bot"></param> /// <param name="message"></param> public virtual void onbotmessage(botshell bot, botmessage message) { } /// <summary> /// returns display name of bot , current version /// </summary> /// <returns></returns> public override string tostring() { return name + " v" + version; } /// <summary> /// there no information document command /// </summary> /// <param name="bot"></param> /// <param name="args"></param> public void fireoncommand(botshell bot, commandargs args) { try { if (args.authorized) oncommand(bot, args); else onunauthorizedcommand(bot, args); } catch (exception ex) { commandargs e = args; var window = new richtextwindow(bot); window.appendtitle("error report"); window.appendhighlight("error: "); window.appendnormal(ex.message); window.appendlinkend(); window.appendlinebreak(); window.appendhighlight("source: "); window.appendnormal(ex.source); window.appendlinkend(); window.appendlinebreak(); window.appendhighlight("target site: "); window.appendnormal(ex.targetsite.tostring()); window.appendlinkend(); window.appendlinebreak(); window.appendhighlight("stack trace:"); window.appendlinebreak(); window.appendnormal(ex.stacktrace); window.appendlinkend(); window.appendlinebreak(); bot.sendreply(e, "there has been error while executing command »» " + window.tostring("more information")); botshell.output("[plugin execution error] " + ex); } } } }
events class:
namespace vhabot.shellmodules { /// <summary> /// vhabot events /// </summary> public class events { public event botstatechangedhandler botstatechangedevent; public event channeljoineventhandler channeljoinevent; public event userjoinchannelhandler userjoinchannelevent; public event userleavechannelhandler userleavechannelevent; public event userlogonhandler userlogonevent; public event userlogoffhandler userlogoffevent; public event privatemessagehandler privatemessageevent; public event privatechannelmessagehandler privatechannelmessageevent; public event channelmessagehandler channelmessageevent; public event memberaddedhandler memberaddedevent; public event memberremovedhandler memberremovedevent; public event memberupdatedhandler memberupdatedevent; public event altaddedhandler altaddedevent; public event altremovedhandler altremovedevent; /// <summary> /// message sent irc channel in response <see cref="vhabot.botshell.sendircmessage" /> request /// </summary> public event ircmessagehandler ircmessageevent; public event configurationchangedhandler configurationchangedevent; internal void onbotstatechanged(botshell bot, botstatechangedargs e) { if (botstatechangedevent != null) try { botstatechangedevent(bot, e); } catch { } } internal void onchanneljoin(botshell bot, channeljoineventargs e) { if (channeljoinevent != null) try { channeljoinevent(bot, e); } catch { } } internal void onuserjoinchannel(botshell bot, userjoinchannelargs e) { if (userjoinchannelevent != null) try { userjoinchannelevent(bot, e); } catch { } } internal void onuserleavechannel(botshell bot, userleavechannelargs e) { if (userleavechannelevent != null) try { userleavechannelevent(bot, e); } catch { } } internal void onuserlogon(botshell bot, userlogonargs e) { if (userlogonevent != null) try { userlogonevent(bot, e); } catch { } } internal void onuserlogoff(botshell bot, userlogoffargs e) { if (userlogoffevent != null) try { userlogoffevent(bot, e); } catch { } } internal void onprivatemessage(botshell bot, privatemessageargs e) { if (privatemessageevent != null) try { privatemessageevent(bot, e); } catch { } } internal void onprivatechannelmessage(botshell bot, privatechannelmessageargs e) { if (privatechannelmessageevent != null) try { privatechannelmessageevent(bot, e); } catch { } } internal void onchannelmessage(botshell bot, channelmessageargs e) { if (channelmessageevent != null) try { channelmessageevent(bot, e); } catch { } } internal void onmemberadded(botshell bot, memberaddedargs e) { if (memberaddedevent != null) try { memberaddedevent(bot, e); } catch { } } internal void onmemberremoved(botshell bot, memberremovedargs e) { if (memberremovedevent != null) try { memberremovedevent(bot, e); } catch { } } internal void onmemberupdated(botshell bot, memberupdatedargs e) { if (memberupdatedevent != null) try { memberupdatedevent(bot, e); } catch { } } internal void onaltadded(botshell bot, altaddedargs e) { if (altaddedevent != null) try { altaddedevent(bot, e); } catch { } } internal void onaltremoved(botshell bot, altremovedargs e) { if (altremovedevent != null) try { altremovedevent(bot, e); } catch { } } internal void onconfigurationchanged(botshell bot, configurationchangedargs e) { if (configurationchangedevent != null) try { configurationchangedevent(bot, e); } catch { } } internal void onircmessage(botshell bot, ircmessageargs e) { if (ircmessageevent != null) { ircmessageevent(bot, e); } try { } catch { } } } }
i've got little go on description of system bit vague i'll give shot.
from description seems have plugin, say
interface iplugin { pluginresult readandexecuteevents(events e); // added asynchronous methods. iasyncresult beginreadandexecuteevents(events e, asynccallback cb, object state); pluginresult endreadandexecuteevents(iasyncresult result); }
with
class pluginresult { public boolean stop; // etc. }
also don't seem using .net events, rather sort of event
class/enumeration.
your old code seems like:
foreach (var eventlist in readevents()) foreach (var plugin in pluginlist) if (plugin.readandexecuteevents(eventlist).stop) break;
you can make asynchronous doing like:
foreach (var eventlist in readevents()) { // seems want, 1 event processed @ time "instance"? block here until unlocked. lockprocess(); var pluginindex = 0; asynccallback handleresult = null; handleresult = delegate(iasyncresult result) { if (pluginlist[pluginindex].endreadandexecuteevents(result).stop) goto stop; pluginindex += 1; if (pluginindex == pluginlist.count) goto stop; events e = (events)result.asyncstate; pluginlist[pluginindex].beginreadandexecuteevents(e, handleresult, e); return; stop: unlockprocess(); }; pluginlist[0].beginreadandexecuteevents(eventlist, handleresult, eventlist); }
so in .net 2 style add beginxxx method , in asynccallback stuff. of course actual plugin multithreading/asynchronisity, if writes file using beginwrite
filestream
etc.
i have conveniently ignored exception handling here.
so, make whole application use asynchronisity can put code in beginrunevents
method, say, following same "apm" pattern. can schedule threadpool if wish.
if not @ looking please provide more code examples/info.
Comments
Post a Comment