Jak zachować a.NET uruchomiona aplikacja konsoli?

Rozważ aplikację konsolową, która uruchamia niektóre usługi w osobnym wątku. Wszystko, co musisz zrobić, to poczekać, aż użytkownik naciśnie Ctrl + C, aby go wyłączyć.

Który z poniższych sposobów jest lepszy?

static ManualResetEvent _quitEvent = new ManualResetEvent(false);

static void Main() {
    Console.CancelKeyPress += (sender, eArgs) => {
        _quitEvent.Set();
        eArgs.Cancel = true;
    };

    // kick off asynchronous stuff 

    _quitEvent.WaitOne();

    // cleanup/shutdown and quit
}

Lub to, używając wątku.SEN (1):

static bool _quitFlag = false;

static void Main() {
    Console.CancelKeyPress += delegate {
        _quitFlag = true;
    };

    // kick off asynchronous stuff 

    while (!_quitFlag) {
        Thread.Sleep(1);
    }

    // cleanup/shutdown and quit
}
Author: intoOrbit, 2010-04-06

8 answers

Zawsze chcesz zapobiec używaniu pętli while, szczególnie gdy zmuszasz kod do ponownego sprawdzania zmiennych. Marnuje zasoby procesora i spowalnia program.

Zdecydowanie powiedziałbym, że pierwszy.

 71
Author: Mike,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-06 16:48:55

Alternatywnie, prostszym rozwiązaniem jest po prostu:

Console.ReadLine();
 30
Author: Cocowalla,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-06 16:49:17

Możesz to zrobić (i usunąć CancelKeyPress obsługę zdarzenia):

while(!_quitFlag)
{
    var keyInfo = Console.ReadKey();
    _quitFlag = keyInfo.Key == ConsoleKey.C
             && keyInfo.Modifiers == ConsoleModifiers.Control;
}
Nie wiem, czy lepiej, ale nie podoba mi się pomysł wywołania Thread.Sleep W pętli.. Myślę, że jest czystsze, aby zablokować wejście użytkownika.
 13
Author: Thomas Levesque,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-06 16:51:25

Wolę używać aplikacji .Run

static void Main(string[] args) {

   //Do your stuff here

   System.Windows.Forms.Application.Run();

   //Cleanup/Before Quit
}

From the docs:

Rozpoczyna uruchamianie standardowej pętli wiadomości aplikacji w bieżącym wątku, bez formularza.

 9
Author: ygaradon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-10 11:46:12

Możliwe jest również zablokowanie wątku / programu w oparciu o token anulowania.

token.WaitHandle.WaitOne();

WaitHandle jest sygnalizowany, gdy token jest anulowany.

Widziałem tę technikę używaną przez Microsoft.Lazur.WebJobs.JobHost, gdzie token pochodzi ze źródła tokenu anulowania WebJobsShutdownWatcher (kontrola plików kończąca zadanie).

Daje to pewną kontrolę nad tym, kiedy program może się zakończyć.

 5
Author: CRice,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-01-22 05:21:41

Wygląda na to, że utrudniasz sprawę. Dlaczego nie po prostu Join wątek po sygnalizacji go zatrzymać?

class Program
{
    static void Main(string[] args)
    {
        Worker worker = new Worker();
        Thread t = new Thread(worker.DoWork);
        t.IsBackground = true;
        t.Start();

        while (true)
        {
            var keyInfo = Console.ReadKey();
            if (keyInfo.Key == ConsoleKey.C && keyInfo.Modifiers == ConsoleModifiers.Control)
            {
                worker.KeepGoing = false;
                break;
            }
        }
        t.Join();
    }
}

class Worker
{
    public bool KeepGoing { get; set; }

    public Worker()
    {
        KeepGoing = true;
    }

    public void DoWork()
    {
        while (KeepGoing)
        {
            Console.WriteLine("Ding");
            Thread.Sleep(200);
        }
    }
}
 4
Author: Ed Power,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-07 17:43:58

Z dwóch pierwszych jest lepiej

_quitEvent.WaitOne();

Ponieważ w drugim wątek budzi się co milisekundę będzie przerzucany do przerwania OS, co jest drogie

 1
Author: Naveen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-06 16:50:06

Powinieneś to zrobić tak, jakbyś programował usługę windows. Nigdy nie użyłbyś instrukcji while zamiast tego użyłbyś delegata. WaitOne() jest zwykle używane podczas oczekiwania na usunięcie wątków.Sleep () - nie jest advisible - Czy myślałeś o użyciu systemu.Zegary.Timer używający tego zdarzenia do sprawdzania zdarzenia wyłączonego?

 0
Author: KenL,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-06 17:22:47