Laden...

Dispatcher: Synchrone Callbacks made easy

Erstellt von AyrA vor 9 Jahren Letzter Beitrag vor 9 Jahren 11.102 Views
AyrA Themenstarter:in
60 Beiträge seit 2010
vor 9 Jahren
Dispatcher: Synchrone Callbacks made easy

Beschreibung:

Das Problem bei Threads ist, dass nicht einfach auf das Form zugegriffen werden kann. Normalerweise möchte man aber nach dem Ende eines Threads die verarbeiteten Informationen anzeigen. Der Dispatcher vereinfacht dies erheblich. Das System funktioniert über callbacks, ähnlich wie bei javascript üblich. Die callbacks können daher inline definiert werden und haben zugriff auf den Zustand der Methode in der sie definiert werden.

Aufruf (mit inline funktionen):


Dispatcher.Dispatch(
delegate(object[] args){System.Threading.Thread.Sleep(10000);args[0]="test";},
delegate(object[] args){labelTest.Text=(string)args[0];},
new object[]{null});

Was macht das
Die erste delegate wird asynchron in einem Thread aufgerufen. Die 10 Sekunden Wartedauer beeinflussen nicht die Anwendung.
Die zweite delegate wird aufgerufen, wenn die erste vorbei ist. Die Argumente sind für beide delegates das selbe Array, der erste Aufruf kann also Parameter in den zweiten Aufruf übergeben.
der zweite Aufruf ist immer synchron zum GUI Thread, sofern mindestens ein Form existiert.
Sollte keins existieren (or SYNCHRONIZE direktive ist nicht gesetzt) dann wird die delegate ebenfalls asynchron aufgerufen, dies macht Sinn für Konsolenanwendungen.

Der object-Parameter dient dazu, Argumente zu übergeben. Der Index muss definiert werden (wenn auch null). Verändern der array werte wird jeweils auf der Referenz ausfegührt, deshalb benötigen Stream.Read Aufrufe auch kein "ref" Schlüsselwort. Das selbe Prinzip wird hier ausgenutzt. Der parameter wird an beide callbacks übergeben.

Der obige Aufruf geht davon aus, dass der Aufruf in einem Form mit einem "labelTest" ausgeführt wird

Abhängigkeiten
Läuft unter .NET 2.0. Ist SYNCHRONIZE definiert, dann wird eine Referenz auf System.Windows.Forms benötigt.

Verwendungszwecke

  • Hintergrundaufgaben einfach planen und ausführen.
  • Events zeitverzögert von Form B nach Form A senden, z.B. wenn Form A eine liste mit einträgen enthält und Form B eine Bestätigung zum verarbeiten aller Einträge einholt, kann A benachrichtigt werden, wenn die Operation abgeschlossen ist.
  • Asynchrones I/O. z.B. bei Socket.BeginConnect.
  • Wrapper für beliebige klassen die keine synchronen callbacks anbieten oder nicht asynchron arbeiten. (Thread, Socket, TcpListener, Console.In,Out,Err).

//Define SYNCHRONIZE if it is a window application.
//Console applications do not need this.
#define SYNCHRONIZE

using System.Threading;

#if SYNCHRONIZE
using System.Windows.Forms;
#endif

namespace Dispatch
{
    /// <summary>
    /// callbacks for Dispatch functions
    /// </summary>
    /// <param name="args">Arguments for callback</param>
    public delegate void DispatchHandler(object[] args);

    /// <summary>
    /// Provides an easy event dispatcher
    /// </summary>
    public static class Dispatcher
    {
        /// <summary>
        /// Runs "Method" asynchronously and calls "Callback" synchronously after it
        /// </summary>
        /// <param name="Method">Method to run async</param>
        /// <param name="Callback">Callback to run sync (if possible, otherwise async)</param>
        /// <param name="Args">Arguments for "Method" and "Callback"</param>
        /// <returns>Thread object for the call (already running)</returns>
        public static Thread Dispatch(DispatchHandler Method, DispatchHandler Callback, params object[] Args)
        {
            //Inline functions in C# are almost as easy as in JS.
            Thread T = new Thread(delegate()
            {
                bool called = false;
                Method(Args);
#if SYNCHRONIZE
                //try to call the method in sync with the application loop.
                for (int i = 0; i < Application.OpenForms.Count && !called; i++)
                {
                    if (!Application.OpenForms[i].IsDisposed)
                    {
                        called = true;
                        Application.OpenForms[i].Invoke(Callback, Args);
                    }
                }
#endif
                //if not called, the call it async.
                if (!called)
                {
                    Callback.Invoke(Args);
                }
            });
            //uncomment the next line if you want this call to terminate,
            //if your application exits
            //T.IsBackground = true;
            T.Start();
            return T;
        }
    }
}

Mögliche Anpassungen

  • Ermöglichen, dass der DispatchHandler einen Rückgabewert haben kann.
  • Ändern des generischen "params object[]" in ein geeigneteres Format.

Schlagwörter: dispatcher, synchron, thread, threads, callback

**:::

K
60 Beiträge seit 2014
vor 9 Jahren

Sowas habe ich gesucht und wollte hier schon fast einen neuen Thread aufmachen. Vielen Vielen Dank!!!