Haupthread ruft mehrer Thread auf in welchen auf Events "gewartet" wird

  • VB.NET
  • .NET (FX) 4.0

Es gibt 22 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Haupthread ruft mehrer Thread auf in welchen auf Events "gewartet" wird

    Hallöchen alle miteinander,

    ich habe folgendes Problem und weiß nicht ob mein Lösungsversuch der sinnvollste ist.

    Ich habe eine Windowsform aus der ich beim Start Threads aufrufe (derzeit 50--> werden aber mehr) In den Threads sind lediglich zwei Sub´s angelegt. Allerdings sollen die Threads im Hintergrund auf Events warten. Die Events werden durch ein externes Programm ausgelöst.Auf das Programm greife ich über eine COM-Schnittstelle zu. Dies funktioniert soweit auch. Allerdings fährt sich der Hauptthread nach einiger zeit fest bzw friert ein.... Wird ein Event bei einem Thread ausgelöst, übergebe ich Parameter an mein Hauptthread und versende von dort dann E-Mails. Habe im Netz viel gefunden mit Delegate und Invoke. Bin mir aber nicht sicher ob ich die richtig anwende.... Hier mal die wichtigstens Sub´s

    VB.NET-Quellcode

    1. Public Class start
    2. Public Delegate Sub Alarmauswertung(ByVal oAnlage As String, ByVal oName As String, ByVal oText As String, ByVal oAdresse As String, ByVal oValue As String, ByVal oKlasse As String, ByVal oGruppe As String, ByVal oTimescomes As Date, ByVal oRechnername As String, ByVal oServer As String, ByVal oAlarmgruppe As String)
    3. Public myDelegate As Alarmauswertung
    4. Public ZenNam_Arr(0) As String
    5. Public DerEventzaehler As Integer = 0
    6. Private Sub start_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    7. For Me.DerEventzaehler = 0 To ZenNam_Arr.Length - 1
    8. Dim alarmeventT As New Alarm_EventsT(nameProject, ZenNam_Arr(DerEventzaehler), Me)
    9. Dim TEventAlarmThread As New Thread(AddressOf alarmeventT.lesen)
    10. TEventAlarmThread.Start()
    11. Next
    12. End Sub
    13. end class
    14. 'Im folgenden kommt die Klasse die als Thread aufgerufen wird
    15. Public Class Alarm_EventsT
    16. Public Sub New(ByVal Proj_Name As String, ByVal Z_Proj As String, ByVal myForm As start)
    17. Try
    18. ePrjname = Proj_Name
    19. eZenPrj = Z_Proj
    20. myFormControl1 = myForm
    21. Catch ex As Exception
    22. End Try
    23. End Sub
    24. Public Sub zAlarm_Proj_AlarmComes(ByVal obItem As AlarmItem) Handles zAlarm_Proj.AlarmComes
    25. Dim _Alarmgruppe As String
    26. Dim oName As String = obItem.Name.ToString
    27. Dim oValue As String = obItem.Tagname.ToString
    28. Dim oTimescomes As Date = obItem.Timecomes
    29. Dim oTimesgoes As Date = obItem.Timecomes
    30. Dim oGruppe As String = obItem.AlarmGroup.ToString
    31. Dim oText As String = obItem.Text.ToString
    32. Dim oKlasse As String = obItem.AlarmClass
    33. Dim oAnlage As String = obItem.Projectname.ToString
    34. Dim fail As Integer = 0
    35. Try
    36. myFormControl1.BeginInvoke(myFormControl1.myDelegate, New Object() {oAnlage, oName, oText, start.TextBox2.Text, oValue, oKlasse, oGruppe, oTimescomes, Rechnername, Server, _Alarmgruppe})
    37. fail = 5
    38. Catch ex As Exception
    39. End Try
    40. End Sub
    41. end class


    Also wie gesagt, es funktioniert zunächst so alles, allerdings nach einiger Zeit fährt sich das ganze fest. Kann es daran liegen, dass die Threads einfrieren da sie einige Zeit "gar nix" machen oder ist der Aufruf it Delegat und Invoke falsch?!?

    Was ich erreichen möchte, ist ein aufruf für ein Hintergundprogramm, welches auf die Events des externen Programm wartet ( kann auch mal Tage dauern oder in ms- Bereich kommen). Dieses muss von dort aus Parameter in mein Hauptptoramm übergeben und auf das Datagridview des Hauptprogrammes zugriff haben.

    Ich danke euch für jeden Tipp!!!

    Carki schrieb:

    Bin mir aber nicht sicher ob ich die richtig anwende
    Jou.
    Poste bitte mal eine präzise Aufgabenstellung / Problembeschreibung, ohne die Worte { VB.NET, Thread } zu verwenden und gib auch keine Lösung vor.
    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!
    Also ich möchte eine Windowsform haben die ein Datagridview enthält. Außerdem soll das Programm auf Events reagieren, welche durch ein externes Programm (kommunikation über COM-Schnittstelle) ausgelöst werden. Um die Events auszulösen gibt es für jede Anlage ein extra Sub

    VB.NET-Quellcode

    1. Public Sub zAlarm_Proj_AlarmComes(ByVal obItem As AlarmItem) Handles zAlarm_Proj.AlarmComes
    2. end sub


    nun muss ich für jedes neue Event aus dem externen Programm meinen Quellcode neu generieren, da ich ja einen neuen "AlarmComes" - Sub implementieren muss. Dies wollte ich mit Hilfe einer Schleife o.ä. umgehen. Der erst Post war meine Überlegung dazu. Funktioniert semi-gut....

    Carki schrieb:

    COM-Schnittstelle
    ist was ganz genau?
    Wer sendet das Event AlarmComes?
    Was beinhaltet AlarmItem?
    Kennst Du die Anweisung AddHandler? Gugst Du hier.
    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!
    Ich greife über eine DLL auf das externe Programm zu, wodurch auch das Event AlarmComes und das Item AlarmItem zur Verfügung steht.

    AlarmItem enthält lediglich mehrere Strings, was für mein Problem allerdings irrelevant ist. Interessant ist, wie ich die Vielzahl der Evente durch Schleifen o.ä. realisieren kann ohne mein Quellcode ständig zu erneuern. Es kommen im Laufe der Zeit immer mehr Events "AlarmComes" dazu... Ich möchte es jetzt durch eine Datenbank realisieren. Neues Event neuer Eintrag in Datenbank neustart des Programms und das Event wird mit angelegt....

    Mit AddHandler habe ich noch nix gemacht und werde es mir gleich mal anschauen.

    Danke schonmal dafür.
    Da hast du Recht, allerdings befinden sich in dem anderen Programm mehrere "Anlagen" welche jeweils ein AlarmComes - Event auslösen. Zu jeder Anlage muss ich ein Event anlegen. Dies möchte ich aber komfortabler haben in dem ich eine Schleife durchlaufen lassen mit allen enthaltenen Anlagen. Somit dachte ich an Threads. Gibt es ähnliche Prozesse wie Backgroundworker o.ä. die mir weiterhelfen könnten? Habe leider von der Thematik Thread, Backgroundworker, Delegate, Invoke etc noch nicht viel Ahnung und lese gerade einiges dazu. Sehe aber leider das Licht am Tunnel noch nicht.

    Carki schrieb:

    mehrere "Anlagen" welche jeweils ein AlarmComes - Event auslösen
    Wie stehen die denn zueinander in Deinem Programm?
    • alle in einer Klasse?
    • alle in Klassen mit gemeinsamer Basisklasse?
    • in völlig unterschiedlichen Klassen?
    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!
    Derzeit waren sie aller in einer Klasse.

    Viele Variablendeklarationen + die dazugehörigen Events

    VB.NET-Quellcode

    1. Public Class start
    2. Dim WithEvents zAlarm_Proj_x As z.Alarm
    3. Public Sub zAlarm_Proj_AlarmComes(ByVal obItem As AlarmItem) Handles zAlarm_Proj.AlarmComes
    4. end sub
    5. end class


    Genau dies versuche ich zu vereinfachen um ein dynamisches Programm zu entwickeln, was beim Hinzufügen von neuen Anlagen keine Änderung des Quellcodes bedeutet.

    ErfinderDesRades schrieb:

    Ich sehe nur eine einzige.
    Jou.
    @Carki und die stimmt noch nicht mal mit dem Handler überein.
    So was:

    VB.NET-Quellcode

    1. Public Class start
    2. Dim WithEvents zAlarm_Proj_x As z.Alarm
    3. Dim WithEvents zAlarm_Proj_y As z.Alarm
    4. Dim WithEvents zAlarm_Proj_z As z.Alarm
    5. Public Sub zAlarm_Proj_AlarmComes(ByVal obItem As AlarmItem) Handles zAlarm_Proj_x.AlarmComes, zAlarm_Proj_y.AlarmComes, zAlarm_Proj_z.AlarmComes
    6. End Sub
    7. End Class
    Allerdings kann Dir jetzt auf die Füße fallen, dass z.Alarm kein ordentliches .NET-Event sendet:

    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. End Sub
    Sender und Event-Argumente.
    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!
    Also ich bin der Meinung die DLL ermöglicht mir es nur auf das externe Programm zu zugreifen. Es ist eine Application die ich zunächst auch erst deklariert und zugewiesen habe. Durch die Implementierung des "AlarmComes" - Ereigniss jeder einzelnen Anlage, kann ich auf die Events jeder einzelnen Anlage reagieren. Die vielen Deklarationen waren in dem alten Quellcode. Ich hatte ja jetzt schon versucht über Threads (für jede Anlage wird ein eigen Thread erstellt) die Deklarationen und AlarmComes - Events zu reduzieren. Ist die Überlegung mit den Threads denn erstmal grundsätzlich falsch?'!?! D.h. Kann man ein Thread nicht dafür nutzen um solche unzähligen Eventdefinitionen zu umgehen? Oder ist mein Problem einfach nur das ich versuche von den "Nebenthreads" wieder auf das "Hauptthread" zu zugreifen.

    P.S. alte Quellcode sah ungefähr so aus. UND es ist so, dass ich pro Anlage eine WithEvents Deklaration und ein dazugehöriges AlarmComes - Event definieren musste.

    VB.NET-Quellcode

    1. Dim WithEvents zAlarm_Proj_1 As z.Alarm
    2. Dim WithEvents zAlarm_Proj_2 As z.Alarm
    3. Dim WithEvents zAlarm_Proj_3 As z.Alarm
    4. .
    5. .
    6. .
    7. Public Sub zAlarm_Proj_1_AlarmComes(ByVal obItem As AlarmItem) Handles zAlarm_Proj_1.AlarmComes
    8. 'mach iwas
    9. end sub
    10. Public Sub zAlarm_Proj_3_AlarmComes(ByVal obItem As AlarmItem) Handles zAlarm_Proj_2.AlarmComes
    11. 'mach iwas
    12. end sub
    13. Public Sub zAlarm_Proj_3_AlarmComes(ByVal obItem As AlarmItem) Handles zAlarm_Proj_3.AlarmComes
    14. 'mach iwas
    15. end sub
    Erster Ansatz:

    VB.NET-Quellcode

    1. Dim WithEvents zAlarm_Proj_1 As z.Alarm
    2. Dim WithEvents zAlarm_Proj_2 As z.Alarm
    3. Dim WithEvents zAlarm_Proj_3 As z.Alarm
    4. .
    5. .
    6. .
    7. Public Sub zAlarm_Proj_1_AlarmComes(ByVal obItem As AlarmItem) Handles zAlarm_Proj_1.AlarmComes, zAlarm_Proj_2.AlarmComes,zAlarm_Proj_3.AlarmComes
    8. 'mach iwas, aber differenziert nach Alarmitem!
    9. end sub
    Weitere, noch verschärftere Vereinfachungen sind denkbar. Nur fehlen mir Informationen. Dies hier etwa:

    VB.NET-Quellcode

    1. Dim WithEvents zAlarm_Proj_1 As z.Alarm
    deklariert nur das z.Alarm - Dingens. Ich müsste aber wissen, wie du es erstellst und zuweist - also irgendwo musst du das Schlüsselwort New auf z.Alarm anwenden, etwa

    VB.NET-Quellcode

    1. zAlarm_Proj_1 = New z.Alarm(adresse, sensor, polizeistation)
    Dein erster Ansatz ändert ja an meinem "Problem" leider nix. Kommt eine neue Anlage hinzu, muss ich im Quellcode den Parameter mit einfügen.... Dies wollt ich ja umgehen!

    Nein das

    VB.NET-Quellcode

    1. zAlarm_Proj_1 = New z.Alarm(adresse, sensor, polizeistation)

    habe ich nie gemacht und es fuktioniert trotzdem immer reibungslos.

    ErfinderDesRades schrieb:

    Erster Ansatz
    war bereits in Post #11.
    @Carki Wieviel Code steht denn in so einem EventHandler? Wie lange dauert sein Aufruf?
    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!
    gut, dann könnte es so gehen:

    VB.NET-Quellcode

    1. for each proj As Project in obzED.Projects.Item(nameProject).Parent.Parent.Projects
    2. addhandler proj.Alarm.AlarmComes, addressof zAlarm_Proj_1_AlarmComes
    3. next
    Das leitet alle Alarme auf zAlarm_Proj_1_AlarmComes.
    Hängt davon ab, welchen Datentyp obzED.Projects.Item(nameProject).Parent.Parent.Projects hat, aber es sollte eigentlich wie gezeigt enumerierbar sein.

    Vermutlich gaht auch:

    VB.NET-Quellcode

    1. for each proj As Project in obzED.Projects
    2. addhandler proj.Alarm.AlarmComes, addressof zAlarm_Proj_1_AlarmComes
    3. next
    diese Parent.Parent-Konstruktion ist eh abenteuerlich
    Das Konstrukt obzED.Projects.Item(nameProject).Parent.Parent.Projects wird angemarkert "Der Ausdruck ist vom Typ "z.Projects" und ist keine Auflistung.

    Habe schon folgendes gemacht, ändert leider nix

    VB.NET-Quellcode

    1. For Each proj As z.Project In obzED.Projects.Item(nameProject).Parent.Parent.Projects
    2. AddHandler proj.Alarm.AlarmComes, AddressOf zAlarm_Proj_1_AlarmComes
    3. Next