Как сохранить консольное приложение .NET?

c# multithreading sleep manualresetevent

40806 просмотра

8 ответа

984 Репутация автора

Рассмотрим консольное приложение, которое запускает некоторые службы в отдельном потоке. Все, что нужно сделать, это дождаться, пока пользователь нажмет Ctrl + C, чтобы выключить его.

Что из следующего является лучшим способом сделать это?

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
}

Или это, используя Thread.Sleep (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
}
Автор: intoOrbit Источник Размещён: 06.04.2010 04:45

Ответы (8)


60 плюса

1160 Репутация автора

Решение

Вы всегда хотите запретить использование циклов while, особенно когда вы заставляете код перепроверять переменные. Это тратит ресурсы процессора и замедляет вашу программу.

Я бы определенно сказал первый.

Автор: Mike Размещён: 06.04.2010 04:48

27 плюса

8891 Репутация автора

В качестве альтернативы, более простое решение просто:

Console.ReadLine();
Автор: Cocowalla Размещён: 06.04.2010 04:49

2 плюса

3854 Репутация автора

Из двух первых лучше

_quitEvent.WaitOne();

потому что во втором поток просыпается каждую миллисекунду и будет включен в прерывание ОС, что дорого

Автор: Naveen Размещён: 06.04.2010 04:50

13 плюса

245574 Репутация автора

Вы можете сделать это (и удалить CancelKeyPressобработчик события):

while(!_quitFlag)
{
    var keyInfo = Console.ReadKey();
    _quitFlag = keyInfo.Key == ConsoleKey.C
             && keyInfo.Modifiers == ConsoleModifiers.Control;
}

Не уверен, что так лучше, но мне не нравится идея вызова Thread.Sleepв цикле ... Я думаю, что чище блокировать ввод пользователя.

Автор: Thomas Levesque Размещён: 06.04.2010 04:51

0 плюса

765 Репутация автора

Вы должны делать это так же, как если бы вы программировали службу Windows. Вы никогда не будете использовать оператор while, вместо этого вы будете использовать делегат. WaitOne () обычно используется при ожидании удаления потоков - Thread.Sleep () - не рекомендуется. Задумывались ли вы об использовании System.Timers.Timer с помощью этого события для проверки на событие завершения работы?

Автор: KenL Размещён: 06.04.2010 05:22

3 плюса

7091 Репутация автора

Похоже, вы делаете это сложнее, чем нужно. Почему бы не просто Joinпоток после того, как вы дали сигнал, чтобы остановить?

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);
        }
    }
}
Автор: Ed Power Размещён: 07.04.2010 05:43

9 плюса

1436 Репутация автора

Я предпочитаю использовать Application.Run

static void Main(string[] args) {

   //Do your stuff here

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

   //Cleanup/Before Quit
}

из документов:

Начинает запуск стандартного цикла сообщений приложения в текущем потоке без формы.

Автор: ygaradon Размещён: 10.11.2014 11:46

0 плюса

9364 Репутация автора

Также возможно заблокировать поток / программу на основе токена отмены.

token.WaitHandle.WaitOne();

WaitHandle сигнализируется, когда токен отменен.

Я видел эту технику, используемую в Microsoft.Azure.WebJobs.JobHost, где токен происходит из источника токена отмены WebJobsShutdownWatcher (наблюдатель файла, который завершает задание).

Это дает некоторый контроль над тем, когда программа может закончиться.

Автор: CRice Размещён: 22.01.2019 05:21
Вопросы из категории :
32x32