MultiThreading und Klassenzugriff

  • .NET 5–6
  • VB.NET

Es gibt 6 Antworten in diesem Thema. Der letzte Beitrag () ist von AiKazuya.

    MultiThreading und Klassenzugriff

    Hallo zusammen,

    Ich habe ein Problem mit Multithreading und Klassen und daher eine kleines Testtool gebaut.
    Es werden 5 Threads durch klick auf einen Button erzeugt und übergebe da die Zahl (1 bis 5) zur Zuordnung.
    Beim Start jedes Threads wird eine Testklasse Instanziert und die Werte in die Properties geschrieben.

    Die klasse macht einfach nur eine Addition von Zahlen.

    Jeder Thread schreibt seine werte in (eigentlich) seine eigene .csv-Datei (siehe auch Dateianhang).
    Wenn ich diese mir anschaue, haben die einzelnen CSV-Dateien die Werte der Anderen Threads, obwohl diese nicht miteinander kommunizieren.

    Wie bekomme ich es hin, dass die Threads die Werte in der Klasse nicht an die anderen Threads weitergibt.
    oder wo liegt hier mein Denkfehler?

    Form1.vb
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class Form1
    2. Public w_(10) As Threading.Thread
    3. Public dt_(10) As DataTable
    4. Dim a(10) As Class1
    5. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    6. Dim test As New Threading.Thread(AddressOf Test_Thread)
    7. test.SetApartmentState(Threading.ApartmentState.STA)
    8. test.IsBackground = True
    9. test.Start()
    10. End Sub
    11. Sub Test_Thread()
    12. For i As Integer = 1 To 2
    13. w_(i) = New Threading.Thread(AddressOf Test_Thread2)
    14. w_(i).SetApartmentState(Threading.ApartmentState.STA)
    15. w_(i).IsBackground = True
    16. w_(i).Start(i)
    17. Next
    18. End Sub
    19. Sub Test_Thread2(worker As Integer)
    20. Dim header As String = "id1;id2;id3;id4" & vbCrLf
    21. My.Computer.FileSystem.WriteAllText(My.Application.Info.DirectoryPath & "\" & worker & ".write.csv", header, False)
    22. Dim b As New Class1
    23. Dim i_max As Integer = 100
    24. For i As Integer = 0 To i_max
    25. Select Case worker
    26. Case 1
    27. Me.Invoke(Sub() ProgressBar1.Minimum = 0)
    28. Me.Invoke(Sub() ProgressBar1.Maximum = i_max)
    29. Me.Invoke(Sub() ProgressBar1.Value = i)
    30. b.work_id2 = 1
    31. Case 2
    32. Me.Invoke(Sub() ProgressBar2.Minimum = 0)
    33. Me.Invoke(Sub() ProgressBar2.Maximum = i_max)
    34. Me.Invoke(Sub() ProgressBar2.Value = i)
    35. b.work_id2 = 2
    36. Case 3
    37. Me.Invoke(Sub() ProgressBar3.Minimum = 0)
    38. Me.Invoke(Sub() ProgressBar3.Maximum = i_max)
    39. Me.Invoke(Sub() ProgressBar3.Value = i)
    40. b.work_id2 = 3
    41. Case 4
    42. Me.Invoke(Sub() ProgressBar4.Minimum = 0)
    43. Me.Invoke(Sub() ProgressBar4.Maximum = i_max)
    44. Me.Invoke(Sub() ProgressBar4.Value = i)
    45. b.work_id2 = 4
    46. Case 5
    47. Me.Invoke(Sub() ProgressBar5.Minimum = 0)
    48. Me.Invoke(Sub() ProgressBar5.Maximum = i_max)
    49. Me.Invoke(Sub() ProgressBar5.Value = i)
    50. b.work_id2 = 5
    51. End Select
    52. b.work_id1 = i
    53. Threading.Thread.Sleep(10)
    54. b.summa()
    55. 'a(worker).summa2()
    56. Dim c As New Class1
    57. c.work_id1 = b.work_id1
    58. c.work_id2 = b.work_id2
    59. c.work_id3 = b.work_id3
    60. c.work_id4 = b.work_id4
    61. c.summa2()
    62. Dim txt As String = c.work_id1 & ";" & c.work_id2 & ";" & c.work_id3 & ";" & c.work_id4 & vbCrLf
    63. My.Computer.FileSystem.WriteAllText(My.Application.Info.DirectoryPath & "\" & worker & ".write.csv", txt, True)
    64. dt_(worker).BeginLoadData()
    65. dt_(worker).Rows.Add(New Object() {b.work_id3})
    66. dt_(worker).EndLoadData()
    67. dt_(worker).AcceptChanges()
    68. Next
    69. End Sub
    70. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    71. For i As Integer = 1 To 5
    72. dt_(i) = New DataTable
    73. dt_(i).TableName = "test"
    74. dt_(i).Columns.Add("id")
    75. a(i) = New Class1
    76. Select Case i
    77. Case 1
    78. ComboBox1.ValueMember = "id"
    79. ComboBox1.DisplayMember = "id"
    80. ComboBox1.DataSource = dt_(i)
    81. Case 2
    82. ComboBox2.ValueMember = "id"
    83. ComboBox2.DisplayMember = "id"
    84. ComboBox2.DataSource = dt_(i)
    85. Case 3
    86. ComboBox3.ValueMember = "id"
    87. ComboBox3.DisplayMember = "id"
    88. ComboBox3.DataSource = dt_(i)
    89. Case 4
    90. ComboBox4.ValueMember = "id"
    91. ComboBox4.DisplayMember = "id"
    92. ComboBox4.DataSource = dt_(i)
    93. Case 5
    94. ComboBox5.ValueMember = "id"
    95. ComboBox5.DisplayMember = "id"
    96. ComboBox5.DataSource = dt_(i)
    97. End Select
    98. Next
    99. End Sub
    100. End Class


    Class1.vb
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class Class1
    2. Private Shared id1 As Integer
    3. Private Shared id2 As Integer
    4. Private Shared id3 As Integer
    5. Private Shared id4 As Integer
    6. Public Property work_id1() As Integer
    7. Get
    8. Return id1
    9. End Get
    10. Set(value As Integer)
    11. id1 = value
    12. End Set
    13. End Property
    14. Public Property work_id2() As Integer
    15. Get
    16. Return id2
    17. End Get
    18. Set(value As Integer)
    19. id2 = value
    20. End Set
    21. End Property
    22. Public Property work_id3() As Integer
    23. Get
    24. Return id3
    25. End Get
    26. Set(value As Integer)
    27. id3 = value
    28. End Set
    29. End Property
    30. Public Property work_id4() As Integer
    31. Get
    32. Return id4
    33. End Get
    34. Set(value As Integer)
    35. id4 = value
    36. End Set
    37. End Property
    38. Public Sub New()
    39. End Sub
    40. Sub summa()
    41. id3 = id1 + id2
    42. 'summa2()
    43. End Sub
    44. Sub summa2()
    45. id4 = id3 + id2
    46. End Sub
    47. End Class


    *Thema verschoben das es nichts mit WPF zu tun hat. Bitte das nächste mal darauf achten. Danke. ~NoFear23m
    Dateien
    • Thread_1.csv

      (1,21 kB, 51 mal heruntergeladen, zuletzt: )

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Nofear23m“ ()

    @AiKazuya Willkommen im Forum. :thumbup:
    Bevor wir hier wüst in multiplen Threads rumstochern, beschreibe mal ganz genau, was da eigentlich passieren soll.
    Gegen eine klare Aufgabenstellung kann man nämlich ordentlich testen. ;)
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Das richtige Tool ist ein Analysetool für ca 20k Router.
    Da ich nicht jeden Router einzeln abfragen möchte, habe ich die Funktionien in eine eigene Sub gepackt und daraus Threads gemacht, die dynamisch erzeugt werden, jenachdem, wie viele Threads man gleichzeitig nutzen möchte.
    in den Threads instanziere ich die Klasse für die Daten des Routers (IP, Passwort, Zertifikatsdaten, etc) und übergebe diese an die Propertys der Klasse.
    Dann wird aus dem Thread heraus die Routerereichbarkeit geprüft
    Ich starte aus dem Thread die Sub für die Abfrage der Router und anschließend verbinde ich mich per SSH (winscp), um die Daten abzufragen.
    in der Sub werden die Propertys der Klasse geändert und anschließend holt der Thread sich die Daten aus der Klasse und speichert die in eine Datenbank.
    Das funktioniert auch soweit, sofern ich nur einen einzigen Thread nutze.
    Bei 2 Threads oder mehr werden die Daten in der Klasse von den anderen Threads überschrieben und ich erhalte Daten eines ganz anderen Routes, als von dem, wo ich hin wollte.

    So verhält sich aber auch das "Testtool" oben.
    mit dem Button1 erstelle ich den Test_Thread und starte diesen.
    von dem Test_Thread werden dann 5 weitere Test_Thread2 erstellt und die Zahl (worker) der For-Schleife mit übergeben.
    In jedem Test_Thread2 wird die Class1 als "b" instanziert.
    Ich übergebe an die "b"-Class1-Propertys dann die Werte entsprechend des "worker".
    b.work_id2 = 1, b.work_id = 2, etc
    Danach beginnt eine For-Schleife und übergebe innerhalb dieser den Wert
    b.work_id1 = i
    Im Anschluss starte ich b.summa() um eine kleine Addition zu starten.

    code kann an sich weg, war nur zum testen:
    Spoiler anzeigen
    ist dies erledigt, wird die Class1 als "c" instanziert.
    Nun die Werte von b.work_id1 an c.work_id1, etc übergeben.

    Dann rufe ich b/c.summa2() auf um eine weiter Addition zu starten, anhand der Werte, welche ja in der Property bereits enthalten sind.
    (wurden ja durch die erste Addition überschrieben)

    ist die zweite Addition durchgeführt, lasse ich mir die Werte in eine CSV ausgeben und muss feststellen, dass die Thread_1.csv Werte vom 2-5 Thread enthält.

    AiKazuya schrieb:

    VB.NET-Quellcode

    1. Public w_(10) As Threading.Thread
    2. Public dt_(10) As DataTable
    3. Dim a(10) As Class1
    Mach Dir eine einzioge Klasse, die w_, dt_ und a enthält, die arbeitet dann nur in sich ohne Quer-Griff.

    AiKazuya schrieb:

    VB.NET-Quellcode

    1. Me.Invoke(Sub() ProgressBar1.Minimum = 0)
    2. Me.Invoke(Sub() ProgressBar1.Maximum = i_max)
    3. Me.Invoke(Sub() ProgressBar1.Value = i)
    Mach da ein einziges Invoke() draus, wo Du nur den Index übergibst.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    AiKazuya schrieb:

    Public Class Class1
    Private Shared id1 As Integer
    Private Shared id2 As Integer
    Private Shared id3 As Integer
    Private Shared id4 As Integer

    Musste ich gerade selber durch debuggen, bis ich das gesehen habe, aber die Class1 Objekte teile sich alle diese 4 Variablen, da die alle Shared sind.
    @Bluespide Gut :!: Ist mir gar nicht aufgefallen.
    @AiKazuya Ich hätte diese Klasse so zusammengeschoben:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class Class1
    2. Public Property work_id1() As Integer
    3. Public Property work_id2() As Integer
    4. Public Property work_id3() As Integer
    5. Public Property work_id4() As Integer
    6. Public Sub New()
    7. End Sub
    8. Sub summa()
    9. work_id3 = work_id1 + work_id2
    10. 'summa2()
    11. End Sub
    12. Sub summa2()
    13. work_id4 = work_id3 + work_id2
    14. End Sub
    15. End Class

    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Bluespide schrieb:


    Musste ich gerade selber durch debuggen, bis ich das gesehen habe, aber die Class1 Objekte teile sich alle diese 4 Variablen, da die alle Shared sind.


    Das war es.
    Wenn die nicht Shared sind, arbeiten die für sich selbst.
    kann so einfach sein ^^
    Danke =)



    RodFromGermany schrieb:


    Public w_(10) As Threading.Thread
    Public dt_(10) As DataTable
    Dim a(10) As Class1

    das werde ich auf jedenfall noch umschreiben, sodass alles wirklich für sich arbeitet und nichts in die Quere kommt.

    RodFromGermany schrieb:

    Mach da ein einziges Invoke() draus, wo Du nur den Index übergibst.

    Auch das werde ich noch anpassen =)