0

我了解 COM 中多线程单元和单线程单元之间的区别。

请看下面的代码:

'VB.NET
Imports Project1
Imports System.Threading

Public Class Form1

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Dim t1 As New Thread(AddressOf PersonTest.Test2)
        Dim t2 As New Thread(AddressOf PersonTest.Test2)
        Dim t3 As New Thread(AddressOf PersonTest.Test2)
        t1.Name = "Test1"
        t2.Name = "Test2"
        t3.Name = "Test3"
        t1.Start()
        t2.Start()
        t3.Start()
    End Sub

End Class

Public Class PersonTest
    Public Shared Sub Test2()
        Try
            Dim c1 As Class1
            c1 = New Class1
            For test3 As Integer = 0 To 10000
                For test As Integer = 0 To 10000
                    Dim test2 As Short = c1.Add(CShort(test))
                    If test2 <> test + 1 Then
                        MsgBox("Problem here")
                    End If
                Next
            Next
            MsgBox("finished")
        Catch ex As Exception

        End Try
    End Sub
End Class

Public Class Person
    Public id As Integer
End Class

'VB6 - Project1.vbp,class1
Public Test2 As Integer

Public Function Add(ByVal TestParameter As Integer) As Integer
Test2 = TestParameter + 1
Add = Test2
End Function

根据我所阅读的内容,我希望出现“MsgBox(“这里的问题”)',因为多个线程可能会不同步地更改 Person.ID 的值,但是我已经多次测试过这个程序,它从来没有发生了。我了解线程“没有任何保证”。上面的代码会在理论上引起问题吗?如果答案是否定的,那么如何修改代码以引起问题?我正在尝试学习如何编写线程安全代码,为了做到这一点,我必须首先了解代码如何成为线程不安全的。

4

2 回答 2

1

您的大多数问题似乎是多个线程没有机会更新一个值。

在每个线程中,您正在创建一个 的新实例Class1,该实例具有自己的 实例Test2,因此您的每个线程都是对其进行操作的唯一线程。

将您的代码更改为此将强制它出现您想要的问题,尽管我不确定这是否回答了您的问题......

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

    Dim pt = New PersonTest

    Dim t1 As New Thread(AddressOf pt.Test2)
    Dim t2 As New Thread(AddressOf pt.Test2)
    Dim t3 As New Thread(AddressOf pt.Test2)
    t1.Name = "Test1"
    t2.Name = "Test2"
    t3.Name = "Test3"
    t1.Start()
    t2.Start()
    t3.Start()


End Sub


Public Class PersonTest

    Private _class As New Class1

    Public Sub Test2()
        Try

            For test3 As Integer = 0 To 10000
                For test As Integer = 0 To 10000

                    Dim test2 = _class.Add(test)
                    If test2 <> test + 1 Then
                        MsgBox("Problem here")
                    End If
                Next
            Next
            MsgBox("Finished")
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try
    End Sub
End Class

Public Class Person
    Public id As Integer
End Class

Public Class Class1

    'VB6 - Project1.vbp,class1
    Public Test2 As Integer

    Public Function Add(ByVal TestParameter As Integer) As Integer
        Test2 = TestParameter + 1
        Add = Test2
    End Function

End Class
于 2013-04-11T10:13:11.367 回答
1

VB6 生成在注册表中标记为单元线程的 COM 组件。“非线程安全”的一个昂贵的词。您创建的线程在 MTA 中,因为您没有调用 Thread.SetApartmentState()。

首先,您实际上并没有测试线程不安全的代码,每个线程都有自己的对象,因为您将其分配为方法中的局部变量。局部变量存储在栈上,每个线程都有自己的栈。只有当多个线程可以读取和写入共享变量时,线程安全才会受到影响。您必须在 Form_Load() 方法中创建对象并将引用存储在表单类的成员中才能获得共享。

COM 并不知道您实际上没有线程问题。它将自动启动一个新线程,即 STA 为 COM 对象提供一个安全的家。您可以在 Debug + Windows + Threads 调试器窗口中看到这些线程。

它会自动将工作线程对 Add() 函数的调用编组到该 STA 线程。按照公寓规则的要求。这很慢,您的代码应该需要一段时间。就像一个实验一样,在启动之前为每个线程调用 SetApartmentState 以将它们切换到 STA。现在不再需要辅助线程并且不需要编组,您会看到代码完成得更快

使用 Class1 的共享实例将是一个更好的测试。但是更新 Test2 变量仍然是线程安全的,因为它位于单元线程对象中。然而,它获得的实际值是随机的,无论线程上次更新它。

于 2013-04-11T11:33:24.330 回答