2013-05-19 2 views
1

У меня есть хорошо установленное консольное приложение в C# 2.0, которое использует архитектуру плагина. На данный момент программа использует базовую многопоточность, которая может запускать несколько экземпляров. Потоки создаются и продолжаются до тех пор, пока приложение не будет остановлено.C# 2.0 Многопоточность с подключаемой архитектурой

Каждый экземпляр может загружать собственное разнообразие плагинов и настраиваться отдельно. Плагины наследуются от базового плагина. Эта система работает много лет. Плагины управляются событиями, все они читают различные события, чтобы узнать, вызваны ли они, если они не возвращаются, и пусть следующий плагин прочитает события, чтобы узнать, вызваны ли они для запуска.

Эта система работает годами. Тем не менее, я хотел бы расширить область многопоточности, чтобы позволить плагинам прослушивать события в асинхронном режиме, а не синхронно. Один из недостатков этой настройки заключается в том, что, когда плагин срабатывает и выполняет свою работу, он блокирует экземпляр. Когда будет запущено следующее событие, он должен дождаться завершения предыдущей работы. Затем это позволит провести следующий процесс.

Что бы я хотел сделать, это выполнить плагин и не ждать завершения процесса, прежде чем перейти к следующему процессу, чтобы начать с события.

Я застрял с .Net 2.0 на данный момент и должен найти решение в этой области. Я просмотрел многочисленные примеры, и я не могу найти тот, который соответствует критериям. Одна из проблем заключается в том, что каждый плагин имеет свое время, которое может потребоваться для обработки, и нет возможности подсчитать процент, который завершен плагин. Плагины начнут и завершат процесс, когда это будет сделано. В зависимости от параметров события и плагина он может занять любой диапазон времени.

Мой вопрос будет тем, что было бы лучшим способом обработки многопоточности в этой ситуации, когда плагины выполняются событиями. Я просмотрел такие страницы, как http://msdn.microsoft.com/en-us/library/2e08f6yc(v=vs.80).aspx, и я могу выяснить, где я мог бы иметь точку входа в архитектуру плагинов, управляемую событиями.

Если у кого есть какие-либо подсказки, я был бы признателен. Отсутствие многопоточности таким образом было ахиллесовой пятой для этого приложения в течение многих лет.

Plugin база: Они содержат некоторые функции, которые вызываются событиями:

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

So. просто уточнить, что вам нужно. Вам нужна архитектура, которая позволяет одновременно запускать несколько плагинов? заставляют плагины манипулировать событиями самим. – 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 события, а какая-то Event класс/перечисление.

Ваш старый код, кажется, что-то вроде:

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

Вы можете сделать это асинхронно делать что-то вроде:

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); 
    } 

Так что в .NET 2 стиля можно добавить метод BeginXXX и его AsyncCallback делает ваши вещи. Конечно, это до фактического плагина, чтобы сделать его многопоточность/asynchronisity, скажем, если он записывает файл с помощью BeginWrite к FileStream и т.д.

Я обычно игнорировал обработку исключений здесь.

Таким образом, чтобы ваше приложение использовало эту асинхроничность, вы можете поместить этот код в метод BeginRunEvents, скажем, следуя тому же шаблону «APM». Затем вы можете запланировать это в threadpool, если хотите.

Если это совсем не то, что вы ищете, предоставьте еще несколько примеров/информации о кодах.

+0

Спасибо за помощь. Я могу отправить вам ссылку моего репозитория и посмотреть, правильно ли я все объяснил. –

+0

Я только что обновил базу плагинов и исходный код класса событий. –

Смежные вопросы