.NET线程不安全的代码

时间:2013-04-11 09:13:26

标签: vb.net com vb6 thread-safety

我理解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的值不同步,但是我已经多次测试了这个程序,它从未发生过。我理解线程“没有任何保证”。上面的代码可能会在理论上引起问题吗?如果答案是否定的,那么如何修改代码以引起问题呢?我正在尝试学习如何编写线程安全代码,为了做到这一点,我必须首先了解代码如何线程不安全。

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:1)

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

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

COM没有意识到您实际上没有线程问题。它会自动启动一个新线程,一个STA可以给COM对象一个安全的家。您可以在Debug + Windows + Threads调试器窗口中看到这些线程。

它会自动编组从工作线程到该STA线程的Add()函数调用。根据公寓规则的要求。这很慢,你的代码需要一段时间。就像一个实验一样,在启动它之前为每个线程调用SetApartmentState以将它们切换到STA。现在不再需要辅助线程,也不需要编组,你会看到你的代码更快地完成了批次

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

相关问题