簡體   English   中英

具有插件體系結構的C#2.0多線程

[英]C# 2.0 Multi-threading with a plug-in architecture

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

每個實例可以加載自己的各種插件,並分別進行配置。 插件是從基本插件繼承的。 多年來,該系統一直像魅力一樣運作。 插件是事件驅動的,它們都讀取各種事件以查看是否被調用,否則返回,並讓下一個插件讀取事件以查看是否被觸發。

該系統已經工作了多年。 但是,我想進一步擴展多線程的范圍,以允許插件以異步方式而不是同步方式監聽事件。 此設置的缺點之一是,一旦插件觸發並執行其工作,它將鎖定該實例。 觸發下一個事件時,它必須等待上一個工作完成。 然后,它將允許進行下一個過程。

我想要執行的操作是執行插件,而不必等到進程結束后再進入下一個由事件開始的進程。

我暫時還停留在.Net 2.0上,必須在該框架中找到解決方案。 我看了無數示例,但找不到符合條件的示例。 問題之一是每個插件都有其自己的處理時間,並且無法計數追蹤插件完成的百分比。 完成后,插件將開始和結束其過程。 根據事件和插件的參數,它可能需要任何時間范圍才能完成。

我的問題是在這種情況下,通過事件執行插件的情況下,處理多線程的最佳方法是什么? 我查看了諸如http://msdn.microsoft.com/zh-cn/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
        {
        }
        }
    }
}

由於您對系統的描述有些含糊,因此我沒有什么可做的,但我會給您一個機會。

從您的描述看來,您似乎有一些插件,例如

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中完成您的工作。 當然,由實際的插件來決定其多線程/異步性,例如是否通過使用BeginWrite將文件寫入FileStream等。

我在這里方便地忽略了異常處理。

因此,要使您的整個應用程序使用這種異步性,可以將代碼放在BeginRunEvents方法中,例如,遵循相同的“ APM”模式。 然后,您可以根據需要將其調度到線程池中。

如果這根本不是您要找的東西,請提供更多代碼示例/信息。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM