【问题标题】:Pass a Class as a parameter when creating a new thread创建新线程时传递一个类作为参数
【发布时间】:2016-04-06 08:18:55
【问题描述】:

为了简短起见,我试图将一个类作为参数传递给另一个线程拥有的另一个方法。这是我的代码的简化:

Friend Sub SplitFile(ByVal fileSplitterSettings As FileSplitterSettingsObject)
        Dim _threadSplitFile As New System.Threading.Thread(Sub() Thread_SplitFile_Start(fileSplitterSettings))          
        _threadSplitFile.Start()
End Sub

SplitFile() 被线程 1 调用,它创建线程 2,传入一个在线程 1 中实例化的对象作为将在线程 2 的上下文中运行的方法的参数。

但是,每当我尝试访问在线程 2 下运行的方法 Thread_SplitFile_Start 中的 fileSplitterSettingsObject 时,我都会收到一条错误消息,指出另一个线程拥有它。

我知道 Dispatcher.Invoke() 以及如何使用它来运行、读取和更改其他线程的方法和对象,但我不确定如何在这里实现。我可以在 Thread_SplitFile_Start 中的 Thread 2 的上下文下创建该类的新实例,并对 Thread_SplitFile_Start 中的每个属性使用 Dispatcher.Invoke() 以便将值从 Thread 1 的上下文中的 fileSplitterSettings 复制到线程 2 的上下文,但这似乎有点矫枉过正,我正在寻找更简单的替代方案。

如果需要任何其他信息,我会很乐意提供。

任何帮助或建议将不胜感激!

编辑:

由于传递整数、字符串等原始类型可以正常工作,我认为传递结构类型可以代替,但这似乎也不起作用。

编辑:

这是我正在使用的这个类。这是我创建的,因此我可以更改任何需要的更改:

Namespace Classes

Friend NotInheritable Class FileSplitterSettingsObject

区域“枚举”

    Friend Enum FileSavingMode
        ModeTogether = 0
        ModeSeparate = 1
    End Enum

结束区域

区域“属性”

    Private _propertyDeleteOriginalFile As Boolean = False
    Private _propertyUseCustomSuffixes As Boolean = False
    Private _propertyFilenameSuffixes As List(Of ListBoxItem)
    Private _propertySavingMode As FileSavingMode = Nothing

    Friend Property DeleteOriginalFile As Boolean
        Get
            Return _propertyDeleteOriginalFile
        End Get
        Set(value As Boolean)
            _propertyDeleteOriginalFile = value
        End Set
    End Property

    Friend Property UseCustomSuffixes As Boolean
        Get
            Return _propertyUseCustomSuffixes
        End Get
        Set(value As Boolean)
            _propertyUseCustomSuffixes = value
        End Set
    End Property

    Friend Property FileNameSuffixes As List(Of ListBoxItem)
        Get
            Return _propertyFilenameSuffixes
        End Get
        Set(value As List(Of ListBoxItem))
            _propertyFilenameSuffixes = value
        End Set
    End Property

    Friend Property SavingMode As FileSavingMode
        Get
            Return _propertySavingMode
        End Get
        Set(value As FileSavingMode)
            _propertySavingMode = value
        End Set
    End Property

结束区域

End Class

结束命名空间

很抱歉没有早点澄清这一点,但我可以在线程 2 中访问“大部分”这些属性。我唯一无法访问的是 FileNameSuffixes,它在线程 1 中设置如下:

For i As Integer = 0 To lbSuffixes.Items.Count - 1
        lbSuffixesItemsList.Add(New ListBoxItem With {
                                                         .Content = CType(lbSuffixes.Items(i), ListBoxItem).Content
                                                     })
Next

我相信这与在线程 1 中实例化 ListBoxItems 有关,这就是线程 2 无法访问它们的原因。基本上,我需要以某种方式将这些项目传递给线程 2,以便我可以访问它们的属性。我知道我可以制作一个 String 类型的列表,它可能会起作用,但很高兴知道我正在尝试做的事情将来是否可以完成(例如,对于同时设置多个属性的对象,不要不想创建一堆基于原始类型的自定义属性只是为了传递信息)

【问题讨论】:

  • 传递一个还是一个实例?看起来更像后者。
  • 线程 1 中声明的类的实例
  • 我收到一个错误声明 ...你能粘贴那个错误吗?
  • 调用线程无法访问该对象,因为不同的线程拥有它:引用 fileSplitterSettingsObject

标签: .net vb.net multithreading thread-safety


【解决方案1】:

这可能太简单了(而且我没有要测试的对象),但我认为 .Invoke 与您的代码看起来像这样:

Dispatcher.Invoke(Sub()
    Dim _threadSplitFile As New System.Threading.Thread(Sub() Thread_SplitFile_Start(fileSplitterSettings))          
        _threadSplitFile.Start()
End Sub)

或者这个:

Dim _threadSplitFile As New System.Threading.Thread(Sub() Thread_SplitFile_Start(fileSplitterSettings))          
Dispatcher.Invoke(Sub()
        _threadSplitFile.Start()
End Sub)

...取决于您在哪里得到错误。

但是 - 您正在创建 2 个线程,这些线程将依次等待主线程执行(因为 fileSplitterSettings 不是线程安全的)。如果我是你,我会考虑重新设计。也许:

  1. 在线程安全类中传递您需要的设置(例如 - 您创建的类)。即使这只是 fileSplitterSettings 之上的一个门面

  2. 在这个线程中创建一个 fileSplitterSettings 对象,然后

  3. 执行 .Start 在同一个线程中。

然后 - 你得到多线程并且不需要与调度程序混淆。同样,可能太简单了,我不知道您的环境/限制。希望至少能给你一些可以玩的东西!

【讨论】:

  • 感谢布赖恩提供的信息。我对您的第一个代码块有疑问。在我的项目中创建线程 2 时,只有一个线程在运行,程序启动时的主线程。调用 Dispatcher.Invoke() 是否会改变线程 2 的运行方式,如果在那之前的所有内容都在线程 1 的上下文中运行?此外,我编辑了我的原始帖子以包含该课程,并提供了一些附加信息。
  • 请看 - 我认为 ListBoxItem 会导致您的耳鸣(因为它是一个愚蠢的 UI 元素,并且 UI 元素归 UI 线程所有,也许吧?)。为这些 fileNameSuffix 值创建自己的字典会是一个巨大的痛苦吗?但是等等,这不是你的实际问题,是不是......对不起。好的。我一直认为 .Invoke 作为“阻止” Thread2 的一种方式,以便 Thread1 可以采取行动(例如 - 您的 UI 将在此期间“冻结”)。理想情况下,我想你会在更新 ListBoxItem 所需的微秒内冻结 UI。很近吗?
  • 我曾认为调用基本上是“要求”特定线程在其上下文中运行特定方法。也就是说,线程 1 可以要求线程 2 运行一个方法,然后继续其快乐的方式。但除此之外,FileNameSuffixes 不必是字典。它可能是一个 ItemCollection 或一个 ListBoxItem 数组(所有这些都不起作用)。简而言之,我只是在寻找一种将包含信息的类传递给另一个线程的方法。如果你知道一个更简单的方法来解决这个问题,我很高兴听到:)
  • 我认为你完全正确(只是在继续之前你正在等待其他线程“回答”)。顺便说一句,Invoke vs BeginInvoke 上有一个cool post。关于您的实际问题(假设您不想使用 Invoke),请尝试使用 Dictionary,伙计。 ItemCollection 和 ListBoxItem 都是 UI 控件(例如 - 您正在传递一个指向 Windows 控件的指针,而不是“数据”)。所以,如果你的列表框是字符串/字符串,你可以使用 Dictionary(string, string) 而不是 ListBoxItem.Content ...
  • 我想我可以这样做,但这只是因为 ListBoxItem 的 Content 属性是一个字符串。如果我想传递一个 UI 控件来提取它的属性怎么办?例如,假设我想传递一个 UIElement ,其中包含我需要读取的 20 多个属性。有没有办法传递一个 UI 对象?
【解决方案2】:

与@Brian Saunders 合作后,我确定最好只使用通用字符串数组来传递那个麻烦的属性。

【讨论】:

    猜你喜欢
    • 2012-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-10
    • 2023-03-26
    • 2021-12-23
    • 2020-08-02
    • 1970-01-01
    相关资源
    最近更新 更多