2013-04-11 2 views
0

Я понимаю разницу между многопоточными квартирами и однопрофильными квартирами в COM.. NET Thread небезопасный код

Пожалуйста, смотрите код ниже:

'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 из синхронизации, однако я тестировал эту программу несколько раз, и ее никогда не было. Я понимаю, что «ничто не гарантировано» нитями. Может ли приведенный выше код вызвать теоретическую проблему? Если ответ отрицательный, то как код может быть изменен, чтобы вызвать проблему? Я пытаюсь научиться писать потокобезопасный код, и для этого я должен сначала понять, как код может быть небезопасным.

+0

Я предполагаю, что вы вызываете его на несколько потоков? Я думаю, что вызов MsgBox должен быть в потоке пользовательского интерфейса (но не в том, что он влияет на вашу проблему с потоками) – Rob

+0

@Rob, код показывает, что три потока создаются в функции обработчика Form.Load. – w0051977

+0

И функция VB6 «Добавить», предположительно, это inproc, а не STA? – Rob

ответ

1

VB6 создает COM-компоненту, которые помечены квартиры резьбовые в реестре. Дорогие слова «не потокобезопасны». Созданные вами потоки находятся в MTA, так как вы не вызывали Thread.SetApartmentState().

Во-первых, вы на самом деле не проверяете код, который является небезопасным, каждый поток получает свой собственный объект, поскольку вы выделяете его как локальную переменную в методе. Локальные переменные хранятся в стеке, каждый поток имеет свой собственный стек. Безопасность потока может быть скомпрометирована только тогда, когда более чем один поток может считывать и записывать в общую переменную. Вам нужно будет создать объект в методе Form_Load() и сохранить ссылку в члене класса формы, чтобы получить общий доступ.

COM не знает о том, что на самом деле у вас нет проблемы с потоками. Он автоматически запустит новую тему, которая является STA, чтобы дать COM-объекту безопасный дом. Эти потоки можно увидеть в окне отладки Debug + Windows + Threads.

И автоматически перенаправляет вызов функции Add() из рабочего потока в этот поток STA. В соответствии с правилами квартиры. Это довольно медленно, ваш код должен занять некоторое время. Как и эксперимент, вызовите SetApartmentState для каждого потока, прежде чем запускать его, чтобы переключить их на STA. Теперь, когда вспомогательная нить больше не требуется и не требуется маршалинг, вы увидите, что ваш код заканчивается лот быстрее.

Использование общего экземпляра Class1 будет лучшим испытанием. Но обновление переменной Test2 по-прежнему является потокобезопасной, поскольку оно находится внутри объекта с резьбой. Фактические значения, которые он получает, однако, являются случайными, независимо от того, какой поток последний раз обновил его.

1

Большая часть вашей проблемы, по-видимому, заключается в отсутствии возможности для нескольких потоков обновлять одно значение.

В каждом потоке вы создаете новый экземпляр Class1, который имеет свой собственный экземпляр Test2, поэтому каждый из ваших потоков является единственным потоком, который работает на нем.

Изменение кода это заставит его Exibit проблемы, которую вы хотите, хотя я не уверен, если это отвечает на ваш вопрос или нет ...

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 
Смежные вопросы