VB.NET 通用跨线程操作的两种不同方法;哪个更好?

发布于 2024-10-17 12:59:05 字数 1800 浏览 2 评论 0原文

VB.NET 2010、.NET 4

您好,

我最近读到有关使用 SynchronizationContext 对象来控制某些代码的执行线程的内容。我一直在使用通用子例程来处理(可能)跨线程调用,例如更新利用 Invoke 的 UI 控件。我是一名业余爱好者,很难理解任何特定方法的利弊。我正在寻找一些关于哪种方法更可取以及原因的见解。

更新:这个问题的部分原因是来自 Control.InvokeRequired 上的 MSDN 页面

更好的解决方案是使用 SynchronizationContext 返回 SynchronizationContext 而不是 跨线程封送控制。

而且,当我环顾四周时,关于为什么大多数关于 SO 上此类问题的问题的答案都建议使用 Invoke 方法而不提及此方法,人们普遍感到困惑。

方法 1:

Public Sub InvokeControl(Of T As Control)(ByVal Control As T, ByVal Action As Action(Of T))
    If Control.InvokeRequired Then
        Control.Invoke(New Action(Of T, Action(Of T))(AddressOf InvokeControl), New Object() {Control, Action})
    Else
        Action(Control)
    End If
End Sub

方法 2:

Public Sub UIAction(Of T As Control)(ByVal Control As T, ByVal Action As Action(Of Control))
    SyncContext.Send(New Threading.SendOrPostCallback(Sub() Action(Control)), Nothing)
End Sub

其中 SyncContext 是在我的 UI 表单的构造函数中定义的 Threading.SynchronizationContext 对象(我将其存储在模块中...不确定这是否是最好的选择):

Public Sub New()
    InitializeComponent()
    SyncContext = WindowsFormsSynchronizationContext.Current
End Sub

然后,如果我想更新 UI 表单上的控件(例如,Label1),我会这样做:

InvokeControl(Label1, Sub(x) x.Text = "hello")

或者

UIAction(Label1, Sub(x) x.Text = "hello")

所以,你们觉得怎么样?是首选一种方式还是取决于上下文?如果您有时间,冗长将不胜感激!

预先感谢,
布莱恩

VB.NET 2010, .NET 4

Hello,

I recently read about using SynchronizationContext objects to control the execution thread for some code. I have been using a generic subroutine to handle (possibly) cross-thread calls for things like updating UI controls that utilize Invoke. I'm an amateur and have a hard time understanding the pros and cons of any particular approach. I am looking for some insight on which approach might be preferable and why.

Update: This question is motivated, in part, by statements such as the following from the MSDN page on Control.InvokeRequired.

An even better solution is to use the
SynchronizationContext returned by
SynchronizationContext rather than a
control for cross-thread marshaling.

And also, general confusion as to why, as I look around, a majority of answers to questions regarding this type of problem on SO suggest the Invoke approach without mentioning this method.

Method 1:

Public Sub InvokeControl(Of T As Control)(ByVal Control As T, ByVal Action As Action(Of T))
    If Control.InvokeRequired Then
        Control.Invoke(New Action(Of T, Action(Of T))(AddressOf InvokeControl), New Object() {Control, Action})
    Else
        Action(Control)
    End If
End Sub

Method 2:

Public Sub UIAction(Of T As Control)(ByVal Control As T, ByVal Action As Action(Of Control))
    SyncContext.Send(New Threading.SendOrPostCallback(Sub() Action(Control)), Nothing)
End Sub

Where SyncContext is a Threading.SynchronizationContext object defined in the constructor of my UI form (I store it in a module... Not sure if that's the best choice):

Public Sub New()
    InitializeComponent()
    SyncContext = WindowsFormsSynchronizationContext.Current
End Sub

Then, if I wanted to update a control (e.g., Label1) on the UI form, I would do:

InvokeControl(Label1, Sub(x) x.Text = "hello")

or

UIAction(Label1, Sub(x) x.Text = "hello")

So, what do y'all think? Is one way preferred or does it depend on the context? If you have the time, verbosity would be appreciated!

Thanks in advance,
Brian

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

仅此而已 2024-10-24 12:59:05

好吧,我一直在做一些阅读,因为我没有得到任何答复,我想我应该开始对我自己的问题进行部分回答,其中包含我迄今为止发现的内容:

我发现了一个 有趣的 codeproject 文章 讨论 SynchronizationContext< 的使用/code> 用于在线程之间编组代码(特别是从工作线程到 UI 线程)。我发现一些有趣的观察结果:

  • UI 线程的 SynchronizationContext 对象是在该线程中创建第一个控件时创建的。在此之前,它没有被定义。
  • UI 线程的 SynchronizationContext 不是 SynchronizationContext 类的实例,而是派生的 System.Windows.Forms.WindowsFormsSynchronizationContext 类的实例来自SynchronizationContext。此类定义了 Post/Send 的行为,允许将代码从一个线程编组到另一个线程。
  • 传递 UI 线程的 SynchronizationContext 而不是使用 Invoke 的一个好处是,您不必在逻辑中保留对 UI 表单的引用来调用它。
  • Post 方法对于完成指标更新之类的事情似乎很有吸引力,因为它是非阻塞的,但是,正如文章指出的,发布代码中引发的异常会在 UI 线程中引发。即,发布到 UI 的代码中的错误可能会使 UI 崩溃。 Send 没有这个问题。发送时抛出的异常在工作线程中抛出。

更新:这是 另一篇富有洞察力的文章。在本文中,Kael Rowan 讨论了一种上下文,在该上下文中使用 SynchronizationContext 可能比控件实例的 Invoke/BeginInvoke 方法更好。他认为,在编写可重用库时,仅仅出于调用目的而必须维护对库外部控件的引用是不可取的。他提供了委托代码,确保创建的任何新线程都将共享 UI 线程的 SynchronizationContext

好吧,看来我不会再在这里收到任何评论了。我在这里写的内容是我的无知使我能够得到的最接近的答案。如果有人还有什么要补充的,我肯定会很感激,但现在我要继续了。 :/

Well, I've been doing some reading and, since I'm not getting any responses, I figured I'd start a partial answer to my own question containing what I've found so far:

I found an interesting codeproject article discussing the use of SynchronizationContext for marshaling code between threads (and specifically from worker threads to the UI thread). Some observations I found interesting:

  • The UI thread's SynchronizationContext object is created upon creation of the first control in that thread. Before that, it is not defined.
  • The SynchronizationContext for the UI thread is not an instance of the SynchronizationContext class, but of the System.Windows.Forms.WindowsFormsSynchronizationContext class which is derived from SynchronizationContext. It is this class that defines the behavior of Post/Send allowing marshaling of code from one thread to another.
  • An appeal of passing the UI thread's SynchronizationContext around rather than using Invoke is that you don't have to keep a reference to your UI form in logic in order to invoke it.
  • The Post method seems appealing for accomplishing things like indicator updates since it's non-blocking, but, as the article points out, exceptions thrown in posted code are thrown in the UI thread. i.e., a bug in code posted to the UI can crash the UI. Send doesn't have this problem. Exceptions thrown when sending are thrown in the work thread.

Update: Here is another insightful article. In this article, Kael Rowan discusses a context in which using SynchronizationContext might be preferable to a control instance's Invoke/BeginInvoke methods. He argues that, when writing a reusable library, it is not desirable to have to maintain a reference to a control outside of the library simply for invokation purposes. He provides code for a delegate that ensures any new thread created will share the UI thread's SynchronizationContext.

Alright, well, it looks like I'm not going to get any more comments here. What I've written here is about as close as my ignorance allows me to get to an answer. If anyone has anything else to add, I'd surely appreciate it, but I'm moving on for now. :/

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文