Devo usare un booleano o un token di cancellazione per fermare questa attività?

3

Ho un programma che avvia un'attività come segue:

token = this.tokenSource.Token;

var t = Task.Factory.StartNew(() =>
{
    while(!token.IsCancellationRequested)
    {
        // do the work...
    }
}, token);

Il mio obiettivo con questa attività è di eseguire alcuni lavori finché l'utente non interrompe il programma. L'utente che interrompe il programma comporterà l'arresto di questa attività dall'esecuzione (come segue):

this.tokenSource.Cancel();

Il thread osserverebbe quindi la sorgente di token annullata e quindi si fermerà. Mi chiedo ... Come è diverso dal fare qualcosa di simile:

private bool isCancelled = false;

public void Start()
{
    var t = Task.Factory.StartNew(() =>
    {
        while (!this.isCancelled)
        {
            // do the work...
        }
    });
}

public void Stop()
{
    this.isCancelled = true;
}

Di solito faccio i miei programmi nel primo modo (che non mi ha ancora deluso), ma ora sono in secondo tempo indovinato per qualche motivo. Sono queste entrambe le cattive pratiche?

    
posta Snoop 12.09.2016 - 20:47
fonte

1 risposta

2

Il secondo non sincronizza correttamente l'accesso alla memoria che stai condividendo tra più thread e, di conseguenza, non funzionerà necessariamente nel modo in cui desideri. Ad esempio, il thread pool di thread che esegue il lavoro può vedere che non sta scrivendo su quella variabile (potrebbe esserci un altro thread, ma non ha bisogno di sapere o preoccuparsi di ciò che fanno gli altri thread quando non c'è esplicito sincronizzazione in corso) e quindi è libero di memorizzare nella cache quel valore booleano invece di scaricarlo dalla memoria ogni volta che ne ha bisogno, cosa che è tanto più probabile che venga fatta data la frequenza con cui legge quel valore. Ciò si tradurrà in esso non notando il cambiamento dall'altro thread, probabilmente per un bel po 'di tempo. E naturalmente il fatto che questo problema non si verificherà ogni tempo farà diagnosticare quando fa è ancora più difficile.

CancellationToken si prende cura di tutte le sincronizzazioni necessarie in modo da non dover , e lo farà nel modo più efficiente possibile per l'avvio.

Spesso è anche vantaggioso dal punto di vista del design. È possibile separare chi è responsabile dell'annullamento dell'operazione da chi è responsabile di agire in base a tale cancellazione. Di conseguenza, vi è un accoppiamento molto più flessibile tra il tuo operatore e il chiamante / consumatore. Quel lavoratore potrebbe lavorare per chiunque che vuole che lavori; non sta legando la cancellazione a una particolare variabile in una particolare posizione. Ciò è tanto più rilevante quando l'entità responsabile della cancellazione dell'operazione è a diversi livelli rimossi dall'entità responsabile del lavoro. È molto più facile passare un token di annullamento a qualcosa che lo passa a qualcosa che lo controlla per vedere quando avviene la cancellazione piuttosto che provare a gestirlo con un semplice booleano; o significa che una di quelle entità ha bisogno di conoscere esplicitamente l'altra, nonostante tutti gli strati di astrazione tra di loro, o richiederebbe l'incapsulamento di quel booleano in qualche modo analogo a quello che CancellationToken fa.

Inoltre, l'astrazione dell'idea di un token di cancellazione consente di creare operazioni di livello superiore che agiscono su / con token di cancellazione. Ti consente di creare un token di cancellazione che verrà annullato dopo un determinato periodo di tempo, o di creare un token di cancellazione che viene annullato solo quando tutti i token sono stati annullati, o quando uno qualsiasi dei token è stato cancellato, ecc. .

    
risposta data 12.09.2016 - 20:52
fonte

Leggi altre domande sui tag