C# Warten auf Event oder Timeout

ML89

Lt. Junior Grade
Registriert
Apr. 2014
Beiträge
440
Guten Morgen,

für eine Aufgabe suche ich gerade einen Weg, auf ein Event oder ein Timeout zu warten. Also es wird eine Methode gestartet, die bei erfolgreicher Ausführung ein Event auslöst, auf das gewartet werden soll. Damit das Programm da aber nicht stecken bleibt, soll es ein zeitliche Begrenzung für die Dauer des Wartens geben. Die Lösung, die man bei Google findet ist mir etwas zu aufwendig. Habt ihr viellicht einen einfacheren Ansatz oder einen Tipp, wo ich mal schauen könnte?
 
Eine asynchrone Methode (oder eine synchrone Methode, die mit Task.Run aufgerufen wird) und dann Task.Wait(timeout).

Du musst dann aber u.U. auch auf Multithreading-Eigenheiten achten.

Code:
   public static void Main()
   {
      var task = Task.Run(() => DoSomething());
      task.Wait(2000);

      var task2 = DoSomethingAsync();
      task.Wait(2000);
   }

   static void DoSomething()
   {
      Thread.Sleep(10000);
   }

   static async Task DoSomethingAsync()
   {
       await Task.Delay(10000);
   }
 
Zuletzt bearbeitet:
Ich löse das immer mit SemaphoreSlim und einem CancellationToken.

Code:
using (var semaphore = new SemaphoreSlim(0, 1)) {
  EventHandler handler = null;
  handler = (s, e) => {
    event -= handler;
    semaphore.Release();
  }
  event += handler;

  semaphore.Wait();
}

Wait kannst du auch asynchron nutzen. Für einen timeout dem Wait einfach das CancellationToken übergeben. Code müsste funktionieren. Hab ihn aber vom Handy getippt.
 
Ich glaube, dass ich etwas ebenso elegantes gefunden habe. Mit Hilfe des AutoResetEvents. Die Methode "DoSomethingAsync" ist dabei die Simulation einer zeitaufwendigen Methode, an dessen Ende das Event "MyEvent" ausgelöst wird. Beim Auslösen des Events wird der Zustand des AutoResetEvents verändert. Innerhalb von MyWaitingMethod wird durch AutoResetEvent.WaitOne(4000) vier Sekunden gewartet, bis es weiter geht oder eben der Status des AutoResetEvents geändert wird. Möchte jetzt nur noch das MyEvent als Parameter an die Methode übergeben können und dann das AutoResetEvent innerhalb der Methode erzeugen. Also alle wichtigen Komponenten nach innen ziehen.

Code:
class Program
    {
        static event MyEventHandler MyEvent;
        static AutoResetEvent autoResetEvent = new AutoResetEvent(false);
        
        static void Main(string[] args)
        {
            MyEvent += new MyEventHandler(OnMyEvent);
            var t = DoSomethingAsync();
            MyWaitingMethod(autoResetEvent);
            Console.ReadLine();
        }

        static void MyWaitingMethod(AutoResetEvent autoResetEvent)
        {
            Console.WriteLine("MyWaitngMethod gestartet");
            autoResetEvent.WaitOne(4000);
            Console.WriteLine("MyWaitingMethod beendet");
        }

        static async Task DoSomethingAsync()
        {
            Console.WriteLine("DoSomethingAsync");
            await Task.Delay(2000);
            Console.WriteLine("SomethingAsyncDone");
            MyEvent();
        }

        static void OnMyEvent()
        {
            autoResetEvent.Set();
        }
    }
}
Ergänzung ()

Ah, zu früh gefreut. In der Konsole wird der Thread durch das AutoResetEvent nicht geblockt. In der UWP schon und zwar für die Dauer von WaitOne() (Was ja so auch in der Database von Microsoft steht);
Ergänzung ()

@Ocram1992: Wie kriege ich jetzt mit, ob das Event oder das Timeout "schuldig" war? Von dem, was ich bisher beobachtet habe läuft das Programm zunächst durch. Wurde das Event ausgelöst, dann wird der Lambda-Ausduck verwendet.
 
Zuletzt bearbeitet:
Hi, ich mache das wie folgt:

Code:
public async Task LDAPAttribute()
        {
                var recommendations = new List<Task<UserPrincipalEx>>()
            {
                MeineMethode(),
            };
                await Task.WhenAll(recommendations);
                // hier dann alles was danach ausgeführt werden soll

            }



public async Task<UserPrincipalEx> MeineMethode()
        {
            return await Task.Run(() =>
            {
               // deine Code ...
                return;
            });
        }

Ist gerade aus einem Projekt kopiert deswegen die Bezeichnungen....
 
Ich würde dem Wait ein CancellationToken geben, welches nach einer Zeit auslöst. Dann wirft die Wait-Methode eine OperationCanceledException welche du abfangen kannst.

Du baust quasi um das ganze noch ein using mit einer CancellationTokenSource, welches nach deinem Timeout auslöst.

Code:
using (CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromSeconds(4))) {
  ... 
  semaphore.Wait(cts.Token);
}

Andere Methode wäre, dass du im Lambda-Ausdruck eine Variable setzt, welche die sagt, dass das Event aufgerufen wurde, bool z. B.
 
Da ich nebenher etwas C für den Mikrokontroller mache habe ich es einfach über eine boolsche variable gelöst. Wird das Event ausgelöst wird die boolsche Variable auf true gesetzt. Die aufrufende Methode wird mit Task.Wait() kurz gestoppt und danach der Wert der boolschen Variable abgefragt. Auf jeden Fall eine sehr unschöne Lösung, aber sie funktioniert bisher.

Ich werde mir die anderen Vorschläge auch mal anschauen, bisher muss ich mein Projekt jedoch von einer anderen Seite weiter bearbeiten, weswegen das gerade etwas in den Hintergrund tritt. Ich danke euch jedenfalls sehr!
 
Zurück
Oben