2013-05-19 46 views
1

我在使用插件體系結構的c#2.0中建立了完善的控制檯應用程序。 截至目前,該程序使用可以運行多個實例的基本多線程。線程被創建並繼續直到應用程序停止。C#2.0使用插件體系結構的多線程

每個實例都可以加載自己的各種插件並單獨配置。 插件從基礎插件繼承。多年來,這個系統一直像魅力一樣。 插件是事件驅動的,它們都讀取各種事件以查看它們是否被調用,如果不是它們返回,並讓下一個插件讀取事件以查看它們是否被調用觸發。

該系統已運行多年。不過,我想進一步擴展多線程的範圍,以允許插件以異步方式而不是同步方式監聽事件。這種設置的缺點之一是,一旦插件觸發並完成其工作,就會鎖定實例。當下一個事件被觸發時,它必須等待先前的工作完成。然後它將允許下一個過程發生。

我想要做的是執行插件,而不必等到進程結束後再繼續下一個進程,以一個事件開始。

我暫時停留在.Net 2.0中,並且必須在該框架中找到解決方案。我看了很多例子,我找不到符合標準的例子。其中一個問題是每個插件都有自己需要處理的時間,並且沒有辦法計算來跟蹤插件完成的百分比。完成後,插件將啓動並結束其進程。根據事件的參數和插件的不同,可以花費任何時間來完成。

我的問題是什麼是在這種情況下插件由事件執行的情況下處理多線程的最佳方式。我查看了諸如http://msdn.microsoft.com/en-us/library/2e08f6yc(v=vs.80).aspx這樣的頁面,我可以找出在事件驅動插件體系結構中我能夠擁有哪個入口點。

如果有人有任何線索,我將不勝感激。以這種方式缺乏多線程一直是這個應用多年來的致命弱點。

插件基地:其中包含的是由事件觸發的一些功能:

using System; 
using VhaBot.Communication; 

namespace VhaBot 
{ 

/// <summary> 
///  Plugin BaseClass, must be inherited by all 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 the Day"; 
    /// </code> 
    /// </example> 
    public string Name 
    { 
     set 
     { 
      if (_locked) 
      { 
       throw new Exception(); 
      } 
      _name = value; 
     } 
     get { return _name; } 
    } 

    /// <summary> 
    ///  Internal name of the plugin 
    /// </summary> 
    /// <example> 
    ///  <code> 
    /// this.InternalName = "VhMotd"; 
    /// </code> 
    /// </example> 
    public string InternalName 
    { 
     set 
     { 
      if (_locked) 
      { 
       throw new Exception(); 
      } 
      _internalName = value.ToLower(); 
     } 
     get { return _internalName; } 
    } 

    /// <summary> 
    ///  Pluigin Version 
    /// </summary> 
    /// <remarks> 
    ///  Versions are stored as integers only. Version 1.0.0 would have a value of 100 
    /// </remarks> 
    /// <example> 
    ///  <code> 
    /// this.Version = 100; 
    /// </code> 
    /// </example> 
    public int Version 
    { 
     set 
     { 
      if (_locked) 
      { 
       throw new Exception(); 
      } 
      _version = value; 
     } 
     get { return _version; } 
    } 

    /// <summary> 
    ///  Author of the plugin 
    /// </summary> 
    /// <example> 
    ///  <code> 
    /// this.Author = "Vhab"; 
    /// </code> 
    /// </example> 
    public string Author 
    { 
     set 
     { 
      if (_locked) 
      { 
       throw new Exception(); 
      } 
      _author = value; 
     } 
     get { return _author; } 
    } 

    /// <summary> 
    ///  List of contributors to the development of the plugin. 
    /// </summary> 
    /// <example> 
    ///  <code> 
    /// this.Contributors = new string[] { "Iriche", "Kilmanagh" }; 
    /// </code> 
    /// </example> 
    public string[] Contributors 
    { 
     set 
     { 
      if (_locked) 
      { 
       throw new Exception(); 
      } 
      _contributors = value; 
     } 
     get 
     { 
      if (_contributors != null) 
      { 
       return _contributors; 
      } 
      return new string[0]; 
     } 
    } 

    /// <summary> 
    ///  Description of the plugin 
    /// </summary> 
    /// <example> 
    ///  <code> 
    /// this.Description = "Provides an interface to the user to view who is online and/or on the private channel."; 
    /// </code> 
    /// </example> 
    public string Description 
    { 
     set 
     { 
      if (_locked) 
      { 
       throw new Exception(); 
      } 
      _description = value; 
     } 
     get { return _description; } 
    } 

    /// <summary> 
    ///  The default <see cref="VhaBot.PluginState" /> of the 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; 
     } 
     get { return _defaultState; } 
    } 

    /// <summary> 
    ///  List of other plugins that a plugin is dependent on to function 
    /// </summary> 
    /// <remarks> 
    ///  Plugins are referred to using their 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; 
     } 
     get 
     { 
      if (_dependencies != null) 
      { 
       return _dependencies; 
      } 
      return new string[0]; 
     } 
    } 

     public Command[] Commands 
    { 
     set 
     { 
      if (_locked) 
      { 
       throw new Exception(); 
      } 
      _commands = value; 
     } 
     get 
     { 
      if (_commands != null) 
      { 
       return _commands; 
      } 
      return new Command[0]; 
     } 
    } 

    internal void Init() 
    { 
     _locked = true; 
    } 

    /// <summary> 
    ///  A plugin has loaded in response to <see cref="VhaBot.ShellModules.Plugins.Load" /> 
    /// </summary> 
    /// <param name="bot"></param> 
    /// /// 
    /// <remarks>Code inside this method will be executed when a plugin is loading</remarks> 
    public virtual void OnLoad(BotShell bot) 
    { 
    } 

    /// <summary> 
    ///  A plugin has unloaded in response to <see cref="VhaBot.ShellModules.Plugins.Unload" /> 
    /// </summary> 
    /// <param name="bot"></param> 
    /// <remarks>Code inside this method will be executed when a plugin is unloading</remarks> 
    public virtual void OnUnload(BotShell bot) 
    { 
    } 

    /// <summary> 
    ///  A plugin has installed in response to <see cref="VhaBot.ShellModules.Plugins.Install" /> 
    /// </summary> 
    /// <param name="bot"></param> 
    public virtual void OnInstall(BotShell bot) 
    { 
    } 

    /// <summary> 
    ///  A plugin as been uninstalled in response to <see cref="VhaBot.ShellModules.Plugins.Uninstall" /> 
    /// </summary> 
    /// <param name="bot"></param> 
    public virtual void OnUninstall(BotShell bot) 
    { 
    } 

    /// <summary> 
    ///  A plugin has been upgraded (Unused) 
    /// </summary> 
    /// <param name="bot"></param> 
    /// <param name="version"></param> 
    /// <remarks>This function is not active</remarks> 
    public virtual void OnUpgrade(BotShell bot, Int32 version) 
    { 
    } 

    /// <summary> 
    ///  Response to a command 
    /// </summary> 
    /// <param name="bot"></param> 
    /// <param name="e"></param> 
    public virtual void OnCommand(BotShell bot, CommandArgs e) 
    { 
    } 

    /// <summary> 
    ///  Response to an unauthorized command 
    /// </summary> 
    /// <param name="bot"></param> 
    /// <param name="e"></param> 
    public virtual void OnUnauthorizedCommand(BotShell bot, CommandArgs e) 
    { 
    } 

    /// <summary> 
    ///  Response to a command help query <see cref="VhaBot.ShellModules.Commands.GetHelp." /> 
    /// </summary> 
    /// <param name="bot"></param> 
    /// <param name="command"></param> 
    /// <returns></returns> 
    /// <remarks>Code inside this method will be executed when help is requested</remarks> 
    public virtual string OnHelp(BotShell bot, string command) 
    { 
     return null; 
    } 

    /// <summary> 
    ///  Response to a 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 to a plugin message 
    /// </summary> 
    /// <param name="bot"></param> 
    /// <param name="message"></param> 
    public virtual void OnPluginMessage(BotShell bot, PluginMessage message) 
    { 
    } 

    /// <summary> 
    ///  Response to a 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 and current version 
    /// </summary> 
    /// <returns></returns> 
    public override string ToString() 
    { 
     return Name + " v" + Version; 
    } 

    /// <summary> 
    ///  There is no information to document this 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 an error while executing this command »» " + 
          window.ToString("More Information")); 
      BotShell.Output("[Plugin Execution Error] " + ex); 
     } 
    } 
} 
} 

活動類:

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> 
    ///  A message was sent to the IRC channel in response to a <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 
     { 
     } 
     } 
    } 
} 
+0

所以。只是澄清你需要什麼。 你想要一個允許你同時執行多個插件的體系結構?由他們自己引發插件handel事件。 – Venson

+0

「我想要做的事情就是執行插件,而不必等到進程結束後才能繼續下一個進程,以一個事件開始。」那麼是什麼阻止你這樣做呢?我沒有看到你在哪裏描述每個插件無法在其自己的線程中運行的原因。 – mbeckish

+0

感謝您的評論。我沒有說它不能完成,我只是想弄清楚如何做到這一點。我之前沒有使用過這種多線程風格。 –

回答

1

我得很少去爲你的系統的描述是有點模糊,但我會給它一個鏡頭。

從你的描述,似乎你有一些插件,說

interface IPlugin { 
    PluginResult ReadAndExecuteEvents(Events e); 

    // Added asynchronous methods. 
    IAsyncResult BeginReadAndExecuteEvents(Events e, AsyncCallback cb, Object state); 
    PluginResult EndReadAndExecuteEvents(IAsyncResult result); 
} 

class PluginResult 
{ 
    public Boolean Stop; 
    // etc. 
} 

還你似乎沒有使用.NET 事件,而是某種class/enumeration/Event class/enumeration。

你的舊代碼似乎是這樣的:

foreach (var eventList in ReadEvents()) 
      foreach (var plugin in pluginList) 
       if (plugin.ReadAndExecuteEvents(eventList).Stop) 
       break; 

你可以讓這個異步做這樣的事情:所以在.NET 2風格

foreach (var eventList in ReadEvents()) 
    { 
     // It seems this is what you want, only one event processed at a time by an "instance"? So 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); 
    } 

你可以添加一些的BeginXXX方法和它的AsyncCallback做你的東西。 當然它是由實際插件做其多線程/ asynchronisity,說,如果它通過使用BeginWriteFileStream

我已經忽略了方便異常處理寫到這裏的文件。

因此,爲了讓您的整個應用程序使用這種異步性,您可以將此代碼置於BeginRunEvents方法中,例如,遵循相同的「APM」模式。如果你願意的話,你可以把它安排到線程池。

如果這不是你想要的,請提供更多代碼示例/信息。

+0

感謝您的幫助。我可以做的是發送給我一個鏈接庫,看看我是否正確地解釋了一切。 –

+0

我剛剛更新了插件庫和事件類源代碼。 –