2015-06-06 16 views
5

ho un thread che chiama uno dei metodi, ora questo metodo esegue una query che può richiedere molto tempo di forse 40 minuti o giù di lì per completare,Annulla un thread che esegue una query lunga

voglio invia scelta aa utente sia in grado di annullare l'operazione (cioè interrompere il filo e fermare la query per rilasciare database).

Devo dire che sto sviluppando un'applicazione WPF usando .net 4.5, SQL SERVER DB e C#.

+1

È necessario utilizzare BackgroundWorker. Permette la cancellazione. –

risposta

4

È necessario utilizzare backgroundworker, è esattamente ciò che si desidera.

Eather trascinalo dalla casella degli strumenti o crealo in code - behind. Supporta l'annullamento, segnala lo stato di avanzamento, avvisa quando è completo e sa se è in esecuzione o meno.

Ecco un esempio.

void method(){ 
     BackgroundWorker worker = new BackgroundWorker(); 
     worker.RunWorkerCompleted += worker_RunWorkerCompleted; 
     worker.ProgressChanged += worker_ProgressChanged; 
     worker.DoWork += worker_DoWork; 
     worker.WorkerSupportsCancellation = true; 
     if(!worker.IsBusy) 
     { 
      worker.RunWorkerAsync(); 
     } 
} 

    void worker_DoWork(object sender, DoWorkEventArgs e) 
    { 
     //do whatever needs to be done on the other thread here. 
     object argument = e.Argument; //if passed argument in RunWorkerAsync(). 
     object result = new object(); 
     e.Result = result; 
     //after making worker global, you can report progress like so: 
     worker.ReportProgress(50); //you can also pass a userState, which can be any object, to show some data already. 
    } 

    void worker_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     //you can update a progress bar in here 
     int progress = e.ProgressPercentage; 

    } 

    void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     //when done 
    } 

    void CancelTheTask() 
    { 
     if (worker.IsBusy) 
     { 
      //make worker global first, but then 
      worker.CancelAsync(); 
     } 
    } 

A cose importanti da guardare: Non usare mai le risorse nel metodo DoWork che non vengono creati al suo interno. Quindi passa le cose di cui hai bisogno in background come argomenti. E le cose create dal backgroundworker non dovrebbero essere impostate su una variabile globale etere, passare per risultato.

per l'annullamento, RunWorkCompleted sarà anche essere licenziato. Ora la query al database è già in esecuzione, in modo che è ancora in esecuzione, anche quando l'applicazione ha perso tutte le risorse ad esso.

Per annullare ciò, è necessario sapere come si esegue la query, ad esempio @S.Akbari menzionato è a senso unico. Entity Framework 6 supporta anche la cancellazione.

Per questo: check this when using Queryable

here is another example

O questo solution senza Entity Framework.

+0

Non è esattamente quello che vuole, questo non cancellerà un _query_. –

+0

assolutamente giusto Henk! Non l'ho letto correttamente, ho modificato la mia risposta con alcune soluzioni già fornite. Siamo andati bezig – CularBytes

2

Utilizzando Task Parallel Library (TPL) è possibile utilizzare il modello Task Cancellation.

+0

Questa è una buona opzione se il processo in background collabora attivamente con l'annullamento e lo controlla regolarmente, ma se questo non è il caso, è necessario un approccio più drastico. – Alejandro

-1

questo è un problema comune. Ma in WPF e WinForm, mi piacerebbe usare BackGroundWorker. Vedi Here

1

Se il thread dell'interfaccia utente sta eseguendo un'operazione a lungo termine, non sarà in grado di elaborare le richieste di interfaccia utente . Questo è anche conosciuto come Non risponde. Utilizzare ThreadPool come questo:

CancellationTokenSource ct;//instantiate it before ThreadPool.QueueUserWorkItem line 
private void operation_Click(object sender, RoutedEventArgs e) 
{ 
    ct = new CancellationTokenSource(); 
    ThreadPool.QueueUserWorkItem(_ => 

     { 
      var result = LongTimeOperation();//set the operation in another thread so that the UI thread is kept responding 
      //use the Dispatcher to "return" to the UI thread 
      Dispatcher.BeginInvoke(new Action(() => 
      { 
      //Use result for example : Label1.Text = result.ToString(); 
      })); 
     }); 
} 

per dare all'utente una scelta di essere in grado di annullare l'utilizzo operazione CancellationTokenSource come questo:

private void cancel_Click(object sender, RoutedEventArgs e) 
{ 
    if (ct != null) 
     { 
     ct.Cancel(); 
     ct= null; 
     } 
} 

Nota: in LongTimeOperation() è necessario disporre di un altro parametro di tipo CancellationToken

private float LongTimeOperation(CancellationToken ct) 
{ 
    if (ct.IsCancellationRequested) 
    return -1; 
    .... 
    .... 
} 

Questa link è utile su Cancellation in thread gestiti.

2

Quando hai bloccato il thread in attesa della query, è inutile interrompere tutto.

Assicurarsi che il SqlConnection della query sia accessibile dall'interfaccia utente e chiuderlo. Abbandona la discussione, terminerà (con un errore che devi eliminare).