[英]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.