2012-09-28 15 views
8

Ho un ciclo while in un servizio Windows che gira per alcune volte x e avvia x chiamate telefoniche dopo averle lette da qualche file. Ora, se voglio creare un'interfaccia utente che offra un'opzione per interrompere le chiamate telefoniche, interrompi il ciclo while ancora prima che sia completato. Come posso farlo?Interrompi un ciclo while utilizzando un evento esterno

Supponiamo che abbia una funzione.

DialCalls(x) 
{ 
    for(int i= 0 ; i<x ; i++) 
    { 
    // Initiate call 
    } 
} 

Ci possono essere 2,3 DialCalls funzioni che funzionano allo stesso tempo in diversi fili come ho fatto filettatura nell'applicazione pure. Quindi, in pratica, qual è il modo migliore per rompere il loop da una pagina web, forse.

+1

Per le persone che suggeriscono 'volatile': http://blogs.msdn.com/b/ericlippert/archive/2011/06/16/atomicity-volatility-and-immutability-are-different-part-three.aspx –

risposta

6

Utilizzando task cancellazione (di nuovo in .net 4):

[Fact] 
public void StartAndCancel() 
{ 
    var cancellationTokenSource = new CancellationTokenSource(); 
    var token = cancellationTokenSource.Token; 
    var tasks = Enumerable.Repeat(0, 2) 
          .Select(i => Task.Run(() => Dial(token), token)) 
          .ToArray(); // start dialing on two threads 
    Thread.Sleep(200); // give the tasks time to start 
    cancellationTokenSource.Cancel(); 
    Assert.Throws<AggregateException>(() => Task.WaitAll(tasks)); 
    Assert.True(tasks.All(t => t.Status == TaskStatus.Canceled)); 
} 

public void Dial(CancellationToken token) 
{ 
    while (true) 
    { 
     token.ThrowIfCancellationRequested(); 
     Console.WriteLine("Called from thread {0}", Thread.CurrentThread.ManagedThreadId); 
     Thread.Sleep(50); 
    } 
} 

http://blogs.msdn.com/b/csharpfaq/archive/2010/07/19/parallel-programming-task-cancellation.aspx Il compito inghiotte eccezioni per cui v'è una certa pulizia di a, forse come IDisposable? About task exceptions

+1

questa è una buona risposta (quindi +1), ma puoi migliorarla includendo alcuni snippet rilevanti dell'articolo. –

4

È possibile scrivere un'istruzione if all'interno del proprio loop per eseguire il polling dello stato dell'evento esterno.

Per esempio, si potrebbe avere una bandiera:

bool break_out = false;

E nel vostro evento esterno, è possibile impostare il flag break_out true:

break_out = true;

Ora nel tuo ciclo, puoi avere:

DialCalls(x) 
{ 
    for(int i= 0 ; i<x ; i++) 
    { 
    // Initiate call 

    if (break_out) { 
     break; 
    } 
    } 
} 
3

Crea un annullamento a sostegno dell'evento:

public event EventHandler<CancelEventArgs> Call; 

Se abbonato esiste e lo annulla, non chiamare:

while (true) 
{ 
    var e = new System.ComponentModel.CancelEventArgs(); 
    if (Call != null) 
    { 
     Call(this, e); 
    } 
    if (!e.Cancel) 
    { 
     // Initiate call 
    } 
    else 
    { 
     break; 
    } 
} 
0

nell'usare una variabile quando a rompere.

private bool _cancel; 

void DialCalls(...) 
{ 
    for (int i=0; i<x; i++) 
    { 
     ... 
     if (_cancel) break; 
     .... 
    } 
} 

private void SomeEventHandler(object sender, EventArgs e) 
{ 
    _cancel = true; 
} 

o

for (int i=0; i<x && !_cancel; i++) 
0

Avere una variabile globale che è volatile

public static volatile bool stop;  
stop=False; 

DialCalls(x) 
{ 
    for(int i= 0 ; i<x && !stop ; i++) 
    { 
    // Initiate call 
    } 
} 

On Button Click => stop =True; 
0

implementare un endpoint sul servizio che accetta un messaggio che alterna un valore booleano globale/static (o qualche altro) variabile, e avere il ciclo all'interno di DialCalls controllare la variabile all'inizio di ogni iterazione. Non interromperà alcuna telefonata attualmente in corso, ma sto scommettendo che non vuoi che il servizio riagganci nel bel mezzo della chiamata, semplicemente non passare a quello successivo. Ciò interromperà anche per tutti i thread; assicurati solo che la variabile stessa sia sicura per i thread (ad esempio, utilizza la parola chiave volatile).

1
while (!_shouldStop) { /* work in progress */ } 

e nel metodo Stop() che dovrebbe essere sulla stessa classe lavoratrice la variabile bool deve essere impostato come vero.

Inoltre, se ci sono camerieri (come AutoResetEvent) devono essere .Set();.