【问题标题】:What is the best way to handle cross-thread events in C#在 C# 中处理跨线程事件的最佳方法是什么
【发布时间】:2013-10-23 17:25:19
【问题描述】:

我正在尝试开发一种从线程触发事件并在主 UI 线程上处理的方法。在事件处理程序中,我将更新 UI,我宁愿不必到处检查 InvokeRequired。

我从搜索中看到了很多关于此的内容,但我还没有在任何地方看到一个可以 100% 工作而不会出现问题的示例。我提出了一个似乎可行的解决方案,并且据我所知,解决了我读过的各种问题。我很想听听人们对此的看法:

public static void SafeInvoke<T>(this EventHandler<T> source, object sender, T args) where T : System.EventArgs
{
    EventHandler<T> handler;

    lock (SyncRoot)
    {
        handler = Volatile.Read(ref source);
    }

    if (handler == null)
    {
        return;
    }

    foreach (Delegate d in handler.GetInvocationList())
    {
        ISynchronizeInvoke target = d.Target as ISynchronizeInvoke;

        if (target == null)
        {
            continue;
        }

        if (target.InvokeRequired)
        {
            target.BeginInvoke(d, new[] { sender, args });
        }
        else
        {
            handler(sender, args);
        }
    }
}

【问题讨论】:

  • 不需要lock(SyncRoot) 部分。因为source 是作为非引用参数传递的,所以除非您明确这样做,否则它不可能被更改。
  • 好吧,有人想到了 InvokeRequired... 这可能看起来很明显,但我还是会提到它。 InvokeRequired 是一种便利——无论如何都不是要求。您不必检查 InvokeRequired 因为您应该能够知道您的代码何时将在单独的线程中执行以及何时不执行。就个人而言,我从不使用 InvokeRequired。我只是确保当我在将在工作线程中运行的代码部分中使用 Invoke,并且当我知道代码在 GUI 线程中运行时我不使用它。这种方法我从来没有遇到过任何问题。只是一个想法。
  • 你的代码坏了。当目标不是 ISynchronizeInvoke 时,您将忽略函数调用。
  • @dizzy.stackoverflow 此外,Invoke 如果从 UI 线程调用,就好了,所以在你不这样做的情况下(希望很少见)不知道你是不是 UI 线程,你可以打电话Invoke 就知道它会正常工作。
  • 使线程不透明绝不是一个错误。订阅者对事件传递的不可避免的陈旧性以及相当大的开销和线程竞争的非零风险毫无抵抗力。至少让它成为可选并实现 .NET 框架类(如 Process 和 FileSystemWatcher)使用的 SychronizingObject 模式。

标签: c# .net multithreading events invoke


【解决方案1】:

如果您在 .Net 3.5 或更高版本中工作,则可以使用 Reactive Extensions。它非常适合这种事情。

http://msdn.microsoft.com/en-us/data/gg577609.aspx

【讨论】:

  • 这怎么能算作答案呢?它甚至远未接近回答所提出的问题。你说 Reactive Extensions 可以很好地解决这个问题?好的,显示一些代码,或者至少是一些代码的链接——而不是 Reactive Extensions 的链接。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-21
相关资源
最近更新 更多