2016-07-08 20 views
-1

Ich muss die Ausführung einer Aufgabe stoppen, wenn der Benutzer die Escape-Taste drückt. Das Problem ist die Aufgabe, ein Verfahren läuft wie:Eine Aufgabe mit langer verschachtelter Schleife stoppen

void Start(){ 

    while(long loop){ 
     while(!userEvent) System.Windows.Forms.Application.DoEvents(); 
     for(another long loop){ 
      while(more loops) 
     } 
    } 
} 

Und alles, was ich habe gerade die Foren zu diesem Thema gelernt, dass CancellationToken verwenden Sie es so behandeln müssen:

if (token.IsCancellationRequested) 
{ 
     // Clean up here, then... 
     "cleanup".Dump(); 
     token.ThrowIfCancellationRequested(); 
} 

Da es so viele Schleifen gibt, wäre es sehr ineffizient und hässlich zu lesen, ob die Löschung angefordert wird.

Die Aufgabe muss aufhören, wenn das Fenster der inneren Ereignisse aus dem so gelesen werden kann ich nicht nur die CancellationToken vor der nächsten Iteration überprüfen, sie müßten ziemlich überall

So sein, ist es eine Möglichkeit, die Aufgabe zu stoppen, egal in welcher Schleife sie ist? Es muss nicht mit CancellationTokens sein, aber es scheint die "Standard" -Methode zu sein.

Auch wurde die Methode Start() zunächst nicht als Aufgabe verwendet, aber das würde es so machen, dass der Hauptthread auch nach dem Schließen des Fensters den Code ausführte, es sei denn, ich benutzte eine Menge if (windowClosed) break, die ebenso unpraktisch waren .

+3

Wenn Sie einen 'throw' verwenden, um abzubrechen, brauchen Sie nur das' if (token.IsCancellationRequested) 'in der inneren Schleife (oder 1 oder 2 Ebenen darüber, abhängig von der akzeptablen Latenz). –

+0

@HenkHolterman Ich glaube, ich habe vergessen hinzuzufügen, dass die Aufgabe gestoppt werden muss, wenn ich das Fenster schließe, von dem die Ereignisse gelesen werden. Dazu würde der Thread im 'while (! UserEvent) ... hängen bleiben, also wäre die Latenz zu groß. – mjgalindo

+0

Ich sehe das Problem/Unterschied nicht. Das OnClosing-Ereignis kann die Abbruchanforderung auslösen, oder? –

Antwort

2

Ausnahme propagiert nur durch, egal wie viele Schleifen Sie sind in.

private void Form1_KeyDown(object sender, KeyEventArgs e) 
{ 
    switch (e.KeyCode) 
    { 
     case Keys.Escape: 
      cancallation.Cancel(); 
      break; 
    } 
} 

private CancellationTokenSource cancallation = new CancellationTokenSource(); 

private void button1_Click(object sender, EventArgs e) 
{ 
    Task.Run(() => 
    { 
     while (...) 
     { 
      for (...) 
      { 
       cancallation.Token.ThrowIfCancellationRequested(); 
      } 
     } 
    }, cancallation.Token); 
} 

private void Form1_FormClosed(object sender, FormClosedEventArgs e) 
{ 
    if (cancallation.IsCancellationRequested == false) 
    { 
     cancallation.Cancel(); 
    } 
} 
+0

Während ich finde, eine Ausnahme zu werfen, nur um aus einer Schleife ein bisschen meh zu bekommen, mag ich diese Lösung. – Neil

1

Dies ist ein Anwendungsfall für die goto Anweisung (siehe https://msdn.microsoft.com/en-us/library/13940fs2.aspx).

void nestedExit() 
    { 
     while (true) 
     { 
      while (true) 
      { 
       while (true) 
       { 
        while (true) 
        { 
         while (true) 
         { 
          goto Done; 
         } 
        } 
       } 
      } 
     } 

    Done: 
     ; 
    } 

Hinweis: Das Semikolon ist notwendig, um die Linie eine Aussage zu machen. Nur das Label und die schließende Klammer kompilieren nicht.