Как прервать программу нажатием клавиши - PullRequest
0 голосов
/ 26 апреля 2020

Я хочу прервать свою программу производителя-потребителя, нажав клавишу T. Я искал много ответов, но не могу понять , почему это не работает.

static void Main(string[] args)
    {
    Buffer buffer = new Buffer();
    Produtor prod = new Produtor(buffer);
    Thread threadProdutor = prod.CriarThreadProdutor();
    Consumidor cons = new Consumidor(buffer, 100000);
    Thread threadConsumidor = cons.CriarThreadConsumidor();

    threadProdutor.Start();
    threadConsumidor.Start();

    threadProdutor.Join();
    threadConsumidor.Join();
    while (Console.KeyAvailable && Console.ReadKey(true).Key == ConsoleKey.T)
    {
        Environment.Exit(0);
    }
}

Я добавил точку останова в свое время, но программа даже туда не добралась.

1 Ответ

3 голосов
/ 26 апреля 2020

После ввода l oop после ваших вызовов Join() потоки уже будут завершены к тому времени, как вы проверите консоль на предмет ввода, поэтому вам придется изменить порядок.

Далее, while l oop будет введен и продолжит работу, только если есть доступный ключ, и он T. Требуется обратное: l oop до доступна клавиша, и она T.

Наконец, Console.ReadKey() блокируется до нажатия клавиши, поэтому вы не сможете нужно также проверить Console.KeyAvailable, если вы не хотите делать что-то еще, пока вы ждете T (например, показать прогресс или проверить, завершены ли потоки самостоятельно).

while (Console.ReadKey(true).Key != ConsoleKey.T)
{
    // Do nothing...
}
// T has been pressed

// Signal to the threads to stop
// Set a flag, Cancel() a CancellationTokenSource, etc.

// Wait for the threads to terminate
threadProdutor.Join();
threadConsumidor.Join();

// Exit the program
Environment.Exit(0);

Для отображения пока вы ждете нажатия клавиши прерывания, вы можете переписать l oop следующим образом ...

TimeSpan progressInterval = TimeSpan.FromSeconds(1);

// complete is a simple flag set by the consumer(s)
// Only call ReadKey() when KeyAvailable so it can't block longer than updateInterval
while (!complete && (!Console.KeyAvailable || Console.ReadKey(true).Key != ConsoleKey.T))
{
    Console.WriteLine($"Current time is {DateTime.Now:HH:mm:ss.fff}");

    Thread.Sleep(progressInterval);
}

Обратите внимание, что у этого недостатка всегда спит весь progressInterval, даже если условие выхода было выполнено до этого. Простой обходной путь - сократить время между проверками до 1 / n, а затем отображать прогресс только после каждой n th проверки ...

TimeSpan progressInterval = TimeSpan.FromSeconds(1);
const int ReadsPerProgressInterval = 10;
TimeSpan sleepTimeout = new TimeSpan(progressInterval.Ticks / ReadsPerProgressInterval);
int readCount = 0;

// complete is a simple flag set by the consumer(s)
// Only call ReadKey() when KeyAvailable so it can't block longer than updateInterval
while (!complete && (!Console.KeyAvailable || Console.ReadKey(true).Key != ConsoleKey.T))
{
    // This won't display progress until after progressInterval has elapsed
    // To display initial progress:
    //     A) change to == 1, or...
    //     B) duplicate progress display to before the loop as well
    if (++readCount % ReadsPerProgressInterval == 0)
        Console.WriteLine($"Current time is {DateTime.Now:HH:mm:ss.fff}");

    Thread.Sleep(sleepTimeout);
}
...