如何通过按键中断程序

How to interrupt a program by a key press

我想通过按 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);
    }
}

我在 while 中添加了断点,但程序甚至无法到达那里。

通过将循环放在 Join() 调用之后,线程将在您检查控制台输入时已经完成,因此您需要颠倒顺序。

此外,while 循环只会进入并继续 运行 如果有可用的密钥并且它是 T。您想要相反的方法:循环 直到 一个密钥可用并且它是 T.

最后,Console.ReadKey() 会阻塞,直到按下一个键,所以你也不需要检查 Console.KeyAvailable,除非你想在等待 [=15= 时做其他事情](例如显示进度或检查线程是否自行完成)。

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);

要在等待中断键时显示进度,可以这样重写循环...

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,然后仅在每次 nth 检查后显示进度...

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);
}