Ho un processo che viene eseguito nella propria thread e può essere avviato/arrestato senza bloccare. Questo alla fine andrà in un servizio di Windows, ma lo sto configurando in un'app console per ora fino a quando non è completamente aggiornato.Utilizzo di un semaforo anziché di un ciclo while. Questo è buono o cattivo?
Dopo la chiamata a Start(), voglio bloccare il thread del programma principale finché non viene premuto Ctrl-C. So che questo funzionerà:
public static void Main(string[] args)
{
bool keepGoing = true;
var service = new Service();
System.Console.TreatControlCAsInput = false;
System.Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e)
{
e.Cancel = true;
service.Stop();
keepGoing = false; // Break the while loop below
};
service.Start();
while(keepGoing)
{
Thread.Sleep(100); // 100 is arbitrary
}
}
Tuttavia, ritengo che la bandiera e il valore del sonno arbitrario fastidio. So che il costo della CPU è praticamente 0 nel ciclo while, ma preferirei avere un blocco "hard" che viene rilasciato non appena viene eseguito il gestore Ctrl-C. Ho ideato il sotto, utilizzando un semaforo per bloccare fino a quando il gestore anonimo Ctrl-C è fatto:
public static void Main(string[] args)
{
var service = new Service();
var s = new Semaphore(1, 1);
System.Console.TreatControlCAsInput = false;
System.Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e)
{
e.Cancel = true;
service.Stop();
s.Release(); // This will allow the program to conclude below
};
service.Start();
s.WaitOne(); // This will not block
s.WaitOne(); // This will block w/o CPU usage until the sempahore is released
}
E 'un brutto disegno? È eccessivo? È pericoloso?
EDIT:
Ho anche collego AppDomain.CurrentDomain.UnhandledException come segue:
AppDomain.CurrentDomain.UnhandledException += delegate {
service.Stop();
s.Release();
};
EDIT 2 °:
Vorrei sottolineare che è fondamentale che il Il metodo Stop()
viene richiamato all'uscita. @Adam Ralph ha un modello perfettamente valido per una console ibrida/servizio, ma non aveva queste informazioni quando rispondeva alla Q.
Se riesci a evitare il ciclo while, dico che vale la pena di proseguire. – ChaosPandion
Per la prototipazione, quest'ultima rappresenta un notevole miglioramento. In un'applicazione di produzione eviterei l'intera idea di pausa "CTRL + C". Usa un segnale per uccidere il thread. Il modo in cui il segnale è 'Set()' dipende dagli altri livelli coinvolti. Tieni questo a mente quando progetti il tuo servizio. Aggiungi un mezzo, come un metodo che può essere chiamato a, a sua volta, chiama 'Set()'. –
@ P.Brian.Mackey: Sebbene questa non sia un'applicazione di produzione, se * fosse *, non sarebbe prudente gestire almeno Ctrl-C con grazia in un'app per console non interattiva? Così com'è, Ctrl-C semplicemente spegnerà il programma senza l'opportunità di ripulire prima di uscire. In definitiva, mi stavo semplicemente chiedendo se la soluzione semaforo per l'opzione "while (flag) Thread.Sleep (...)". –