Announcement

Collapse
No announcement yet.

Zugriff auf den Hauptthread

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Zugriff auf den Hauptthread

    Hallo


    Ich habe ein Threading-Problem.

    Ich möchte aus einem Thread in einer Klasse ein Event aufrufen.
    Dieses Event soll dann später mal zb. Eine Listbox ändern.
    Wenn ich nun aus dem Thread einen Raiseevent aufruf mache, dann bekomme ich einen IllegalCrossThreadCall fehler.

    Wie kann den Aufruf des Events aus dem Hauptthread erfolgen lassen.

    Ich habe da schon ein wenig mit Delegates probiert, war aber alles erfolglos.

    Code:
    Public Class Megaklasse
      '.... Ein Paar Methoden
    
      Public Event TuWas(byval EinParameter as String)
    
      Private Sub DieseMethodeWirdInEinemSeperatenThreadAusgeführt()
        Raiseevent TuWas("Hallo")
      End Sub
    
    End Class
    Jetzt kommt der Code für das WinForm

    Code:
      Private WithEvents MegaInstanz as New Megaklasse
    
    
      Private Sub HierIstDas_TuWas(byval EinParameter as String) Handles MegaInstanz.TuWas
       IrgenEineListe.Items.Add(EinParameter)
      End Sub

    Ich könnte natürlich in der Methode "HierIstDas_TuWas" mit der Invoke-Methode arbeiten, aber das ist eigentlich die Aufgabe der Klasse.

    Wenn Ihr noch weitere Informationen braucht um mir zu helfen, dann schreibt mich einfach an.

    Ich bedanke mich schon mal bei euch.

    Gruß

    Maurice

  • #2
    Ich könnte natürlich in der Methode "HierIstDas_TuWas" mit der Invoke-Methode arbeiten, aber das ist eigentlich die Aufgabe der Klasse.
    Könntest du das genauer erläutern. Eigentlich ist das Arbeiten mit Invoke an dieser Stelle genau das was man tun sollte. Warum möchtest du das nicht?

    Comment


    • #3
      Die Klasse die ich dort programmiere ist ein Teil einer DLL die wir in unserer Firma verkaufen möchten.

      Wenn wir nun eine solche DLL verkaufen, müssten wir dem Kunde sagen, dass immer dort ein Invoke gemacht werden soll.
      Besser wäre doch, wenn die Klasse das schon intern selbst erledigt.
      Die frage ist nur wie?

      Comment


      • #4
        Da geht mir leider die VB Kenntnisse ab wie das dort aussieht.
        Würde dir C# Code weiterhelfen?

        Ansonsten ist der Trick den Delegaten selbst per Invoke im aufrufenden Thread auszuführen womit dann der Invoke im EventHandler unnötig ist.
        Damit das sauber funktioniert muß du dann aber deine ~Megaklasse~ an kritischen Stellen gegen CrossThread Calls absichern.
        Je nachdem was dann damit getan wird also z.B mehrere EventHandler an den Delegaten hängen oder häufiges an- bzw. abhängen von EventHandlern ist dann nicht mehr wirklich performant. Vielleicht braucht ja ein EventHandler auch gar keine Synchronisierung weil gar nicht auf GUI Elemente zugegriffen wird. Eigentlich kann letztlich nur derjenige entscheiden ob Synchronisierung notwendig ist oder nicht der den Event fängt(bei dir also die HierIstDas_TuWas Methode). Deshalb überlassen auch diejenigen Komponenten im NET Framework die Events aus Threads werfen dem Aufrufer das Synchronisieren.
        Z.B. System.Threading.Timer oder System.IO.Ports.SerialPort

        Überleg dir also gut ob dein Vorhaben wirklich eine gute Idee ist.

        Comment


        • #5
          Hmmm Okay

          Klar kannst du auch C# Code posten.

          Ich habe gedacht das dieses Problem einfacher zu lösen wäre.

          Die Klasse System.Windows.Forms.Form enthält auch eine Invoke-Methode.
          Wenn ich dadurch eine Methode aufrufe, dann wird diese in dem Thread des Forms aufgerufen. Ich habe mir dann gedacht das kann man bestimmt auch selber programmieren.

          MeineKlasse.Invoke

          Ist sowas nicht denkbar?

          Comment


          • #6
            Ist sowas nicht denkbar?
            Darauf läuft es letztlich hinaus aber wie gesagt man muß ein paar Dinge beachten damit das sauber klappt.

            Als erstes brauchen wir einen Event der von deiner Megaklasse veröffentlicht wird und später im Thread des EventHandlers ausgeführt wird. Man bedenke es könnte mehrere EventHandler in verschiedenen Threads geben, denn Events sind ja immer Multicast Events. Damit das hinzufügen von EventHandlern zum Event nicht mit dem feuern des Events kollidiert muß das hinzufügen/abhängen mit einer Critical Section abgesichert werden, denn selben Lock verwenden wir später beim feuern des Events wieder.

            Code:
            private readonly object myEventLock = new object();
            private EventHandler myEvent;
            
            public event EventHandler MyEvent
            {
                add
                {
                    lock (myEventLock)
                    {
                        myEvent += value;
                    }
                }
                remove
                {
                    lock (myEventLock)
                    {
                        myEvent -= value;
                    }
                }
            }
            Da wir nun einen Event haben brauchen wir noch eine Methode die das feuern des Events übernimmt. Hier wird wieder die critical section geöffnet und dann die Liste der EventHandler durchlaufen. Die Empfänger der einzelnen Events werden überprüft ob sie ISynchronizeInvoke implementieren(dann haben sie eine Invoke Methode). Wenn dieser ISynchronizeInvoke implementiert und einem anderen Thread angehört so wird der gesamte Eventhandler in diesem Threadcontext ausgeführt sonst wird der einzelne Eventhandler einfach aufgerufen.

            Code:
            protected void OnMyEvent(EventArgs args)
            {
                if(myEvent)
                {
                    lock (myEventLock)
                    {
                        if(myEvent)
                        {                       
                            foreach (EventHandler eventHandler in myEvent.GetInvocationList())
                            {
                                ISynchronizeInvoke target = eventHandler.Target as ISynchronizeInvoke;
            
                                if ((target != null) && (target.InvokeRequired))                    
                                    target.Invoke((MethodInvoker)delegate() { eventHandler(this, args); }, null);                    
                                else
                                    eventHandler(this, args);
                            }
                        }
                    }
                }
            }

            Comment

            Working...
            X