【问题标题】:C# multiple sources, different threads, one event handlerC# 多源、不同线程、一个事件处理程序
【发布时间】:2010-08-10 08:26:09
【问题描述】:

我需要在线程和事件引发方面具有高超技能的人。

我有一个抽象类A 和两个具体类C1C2(例如插件)。

由于我需要它们相互通信,例如“plugin-application”“plugin-plugin”通信,我在抽象类中有一个方法ExecuteCommand 应该可以完成此操作。此函数向应用程序发出event 以处理某个命令并返回结果(例如,如果一个插件需要来自应用程序的数据,它会从基础调用ExecuteCommand 并等待事件处理程序附带的结果在应用程序上处理)。

protected object ExecuteCommand(SvcCmdType cmdType, params object[] inputParams)
{
  // this code has been simplified
  SvcCommandEventArgs eventArgs = new SvcCommandEventArgs(cmdType, inputParams);

  // generate processing command event (it requires to fill in the result)
  OnProcessingAppCommand(this, eventArgs);

  return eventArgs.OutputParamsList; 
}

问题是:

如果C1C2 背后都有不同的线程,并从它们自己的线程内部同时调用ExecuteCommand,那么我的设计肯定会被破坏,返回的结果会出乎意料。

这种场景的最佳设计是什么?我正在考虑在 ExecuteCommand 内部使用异步调用,例如使用 AsyncOperation... 但这是正确的方法吗?

已编辑: 我想我正在寻找:同步还是异步方式更适合我的场景?或者,我应该在插件线程中处理应用事件处理程序还是在主线程中的某处同步?

非常感谢您对您的建议做出一些很好的解释

谢谢。

【问题讨论】:

    标签: c# multithreading events plugins synchronization


    【解决方案1】:

    在公共资源或代码块上进行线程同步的常用简单方法是使用互斥体(或者,在这种情况下,是临界区)。使用lock语句:

    http://msdn.microsoft.com/en-us/library/c5kehkcz(VS.71).aspx

    这篇文章说要对“this”指针进行锁定,但这可能很危险,因为外部调用者也可能获得相同的锁定,这可能会破坏您的程序。锁定私有类变量。

    以下是您的示例代码的一些修改,以包含锁定/关键部分:

    class SomeClass : ISomeInterface
    {
      protected object ExecuteCommand(SvcCmdType cmdType, params object[] inputParams)
      {
        lock(executeCommandLock)
        {
          SvcCommandEventArgs eventArgs = new SvcCommandEventArgs(cmdType, inputParams);
          OnProcessingAppCommand(this, eventArgs);
          return eventArgs.OutputParamsList; 
        }
      }
    
      private Object executeCommandLock = new Object();
    }
    

    编辑:

    (从 cmets 转述)。您提到您可能希望在单个线程上异步处理对 ExecuteCommand 的所有调用。您可以使用 Dispatcher 类来完成此操作:

    http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.aspx

    在一个线程上获取对调度程序的引用。将该引用传递给其他线程。当这些线程想要调用 ExecuteCommand 时,它们使用 dispatcher.BeginInvoke。由于他们使用 BeginInvoke,所有对 ExecuteCommand 的调用都将异步操作,而不是阻塞在该线程上。但是,每个版本的 ExecuteCommand 都会排队,并按顺序运行调度程序线程。

    【讨论】:

    • @Cristi:异步调用是带有包装器的线程。它们仍然同时执行。如果它们共享任何状态(它们调用的任何函数修改/读取相同的变量),您必须同步线程/异步调用。你也不能简单地测试所有的错误,因为多线程是不确定的。您的应用程序只会在正确(错误)的条件下崩溃。根据墨菲定律,这将发生在南极洲客户的机器上。
    • @Cristi:对于同步与异步,如果您设法为每个线程/调用提供自己的一组状态,您仍然可以支持异步。如果他们不分享任何东西,他们就不能互相破坏。
    • @Cristi:根据您的代码,您可能能够使临界区更小,因此您只会在多个线程尝试访问该单个资源时阻塞。
    • 嗨梅林。你的回答很有帮助。我理解你提出的想法。我现在不确定这个解决方案对我来说是否足够,或者是否有更好的方法。使用“锁”,我们将在内部线程中处理事件处理程序。您知道如何从外部执行事件处理程序,只有一个同步线程,而不是 C1,..,Cn 内部线程?
    • @Cristi:哦,听起来你希望 ExecuteCommand 被异步调用,而不是阻塞。我很困惑,不知何故,我以为你的意思是你想让 C1,...,Cn 异步,它们已经是:) .NET 中可能有一些东西可以做你所要求的(调度员?)。跨度>
    猜你喜欢
    • 1970-01-01
    • 2010-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多