VB.NET通用交叉线程操作的两种不同方法;哪个更好? [英] VB.NET Two different approaches to generic cross-threaded operations; which is better?

查看:169
本文介绍了VB.NET通用交叉线程操作的两种不同方法;哪个更好?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

VB.NET 2010,.NET 4

你好,



我最近读了关于使用 SynchronizationContext 对象来控制某些代码的执行线程。我一直在使用泛型子例程来处理(可能)跨线程调用,例如更新使用 Invoke 的UI控件。我是一个业余爱好者,很难理解任何特定方法的优缺点。我正在寻找一些有关哪种方法可能更可取的见解,以及为什么。

更新:这个问题的动机部分来自于关于MSDN页面 Control.InvokeRequired


更好的解决方案是使用
SynchronizationContext 返回的
SynchronizationContext ,而不是
控件,线程编组。


另外,当我环顾四周时,为什么大多数关于这类问题SO建议 Invoke 方法,而不提及此方法。



方法1:

  Public Sub InvokeControl(Of T As Control)(ByVal Control As T,ByVal Action A (Action)(Of T))
If Control.InvokeRequired Then
Control.Invoke(New Action(Of T,Action(Of T))(AddressOf InvokeControl),New Object(){Control,Action} )
其他
动作(控制)
结束如果
结束小组

方法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 是一个 Threading.SynchronizationContext 对象定义在我的UI窗体的构造函数中(我将它存储在模块中......不知道这是否是最佳选择):

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

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

$ p $ InvokeControl(Label1,Sub(x)x.Text =hello)

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

你们都在想什么?一种方式是首选还是取决于上下文?如果您有时间,请详细了解详细情况!



预先感谢,

Brian

解决方案

嗯,我一直在做一些阅读,因为我没有得到任何答复,我想我会开始对自己的问题的部分回答,至今已发现:



我发现了一个有趣的codeproject文章讨论使用 SynchronizationContext 来封送线程之间的代码(特别是从工作线程到UI线程)。我发现一些有趣的观察结果:


  • UI线程的 SynchronizationContext 对象在创建时创建该线程中的第一个控件。

  • UI线程的 SynchronizationContext 不是的实例, SynchronizationContext 类,但是类的 System.Windows.Forms.WindowsFormsSynchronizationContext 类同步上下文。正是这个类定义了 Post / Send 的行为,允许将代码从一个线程编组到另一个线程。

  • 传递UI线程的 SynchronizationContext 而不是使用 Invoke 您不必为了调用而在逻辑中保留对UI表单的引用。

  • Post 方法似乎很吸引人因为它是非阻塞的,所以可以完成像指标更新这样的事情,但正如文章指出的那样,发布代码中抛出的异常在UI线程中抛出。即发布到UI的代码中的错误可能会导致UI崩溃。 发送没有这个问题。





    更新:这是<一篇关于使用SynchronizationContext的MSDN文章>另一篇有见解的文章一>。在本文中,Kael Rowan讨论了使用 SynchronizationContext 可能优于控件实例的 Invoke / BeginInvoke 方法。他认为,在编写可重用的库时,仅仅为了调用目的而不得不维持对库之外的控件的引用。他为委托提供代码,以确保创建的任何新线程将共享UI线程的 SynchronizationContext



    好的,好吧,看起来我不会在这里得到更多的评论。我在这里写的是关于我的无知让我得到答案。如果任何人有其他补充,我一定会感激,但我现在继续前进。 :/


    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

    解决方案

    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. :/

    这篇关于VB.NET通用交叉线程操作的两种不同方法;哪个更好?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆