英文:
Creating a console app that writes line of output and exits upon Ctrl+C
问题
我想创建一个控制台应用程序,在使用 Ctrl+C 终止时,在输出的最后一行显示一个“摘要语句”,但我在使其正常工作方面遇到了问题。这可能部分是因为我试图创建的应用程序在一个 while(true)
循环中不断写入输出。我可以通过一个简单的示例来最好地说明这个问题:
假设我有一个控制台应用程序,它不断输出当前时间:
while (true)
{
var now = DateTime.Now;
Console.Write(now);
Console.Write(" ");
Console.Write(now.Millisecond);
Console.CursorLeft = 0; // 覆盖同一行
}
这可以正常工作,我可以使用 Ctrl+C 终止应用程序:
23/02/2023 23:07:14 658
现在,当我按下 Ctrl+C 时,我希望文本 Goodbye!
作为输出的最后一行显示出来:
23/02/2023 23:09:56 441
Goodbye!
但是,我在使这个正常工作方面遇到了问题。以下是我的第一次尝试:
Console.CancelKeyPress += OnCancel;
while (true)
{
var now = DateTime.Now;
Console.Write(now);
Console.Write(" ");
Console.Write(now.Millisecond);
Console.CursorLeft = 0; // 覆盖同一行
}
void OnCancel(object? sender, ConsoleCancelEventArgs e)
{
Console.WriteLine("Goodbye");
}
然而,这导致了混乱的输出,例如:
Goodbye023 23:14:55 670
23/02/2023 23:14:55
我认为这是因为 Console.CancelKeyPress
事件处理程序在一个单独的工作线程上执行,并且对 Console.WriteLine("Goodbye");
的调用可以在 while 循环的任何点发生。理想情况下,CancelKeyPress
事件处理程序不应该在 while 循环的当前迭代完成之前运行。我不确定如何以线程安全的方式实现这一点。
我尝试了不同的方法,我不会列出它们的代码,但总结一下,我尝试了以下方法,但都没有成功:
-
在顶层范围中定义一个布尔变量
cancelRequested
,将while
循环条件设置为!cancelRequested
;在OnCancel
中将变量设置为true
;在循环后使用Console.WriteLine("Goodbye!")
。这会导致在Console.WriteLine("Goodbye!")
行上阻塞(死锁?)。 -
类似于上述方法,但使用
CancellationTokenSource
而不是布尔变量。观察到相同的死锁行为,因此我认为这是等效的。
英文:
I want to create a Console app that outputs a 'summary statement' as the last line of output, when it is terminated using <kbd>Ctrl+C</kbd>, but I'm having trouble getting this working. This may be in part due to app I'm trying to create is constantly writing output in a while(true)
loop. I can best illustrate the problem with an simple example:
Let's say I have a console app that constantly outputs the current time:
while (true)
{
var now = DateTime.Now;
Console.Write(now);
Console.Write(" ");
Console.Write(now.Millisecond);
Console.CursorLeft = 0; // Overwrite the same line
}
This works and I can terminate the app with <kbd>Ctrl+C</kbd>:
23/02/2023 23:07:14 658
Now when I press <kbd>Ctrl+C</kbd> I want the text Goodbye!
displayed as the final line of output:
23/02/2023 23:09:56 441
Goodbye!
However, I'm having trouble getting this working. Here's my first attempt:
Console.CancelKeyPress += OnCancel;
while (true)
{
var now = DateTime.Now;
Console.Write(now);
Console.Write(" ");
Console.Write(now.Millisecond);
Console.CursorLeft = 0; // Overwrite the same line
}
void OnCancel(object? sender, ConsoleCancelEventArgs e)
{
Console.WriteLine("Goodbye");
}
However, this results 'garbled' output, for example:
Goodbye023 23:14:55 670
23/02/2023 23:14:55
I think this is happening because the Console.CancelKeyPress
event handler is executed on a separate worker thread and the call to Console.WriteLine("Goodbye");
can happen at any point within the while loop. Ideally the CancelKeyPress
event handler isn't ran until current iteration of the while
loop is finished. I'm not sure how to do this in a thread-safe way.
I've tried different approaches, and I won't listed code for them, but in summary all of the following I've tried to no avail:
- Defined a boolean variable
cancelRequested
in the top scope and setwhile
loop condition to!cancelRequested
; InOnCancel
set the var totrue
;
Console.WriteLine("Goodbye!")
after the loop. This blocks on the
Console.WriteLine("Goodbye!")
line (deadlock?). - Similar to above but used
CancellationTokenSource
instead of a boolean variable.
Same deadlock behavior is observed, so I guess this is equivalent?
答案1
得分: 2
正如评论中@NetMage所指出的,我第一次尝试使用布尔变量来解决乱码文本问题的尝试并没有成功,因为通常按下<kbd>Ctrl+C</kbd>在CancelKeyPress
结束时会终止应用程序,我没有意识到我需要通过将ConsoleCancelEventArgs.Cancel
设置为true
来抑制默认行为。现在我知道了这一点,我有一个有效的解决方案:
Console.CancelKeyPress += OnCancel;
bool cancelRequested = false;
while (!cancelRequested)
{
var now = DateTime.Now;
Console.Write(now);
Console.Write(" ");
Console.Write(now.Millisecond);
Console.CursorLeft = 0; // 覆盖同一行
}
Console.WriteLine();
Console.WriteLine("Goodbye");
void OnCancel(object? sender, ConsoleCancelEventArgs e)
{
e.Cancel = true; // 阻止取消按键终止应用程序
cancelRequested = true; // 通知主循环请求取消
}
英文:
As pointed out by @NetMage in the comments, my first attempt to solve the issue with the garbled text using a boolean variable was not working because normally pressing <kbd>Ctrl+C</kbd> terminates the app at the end of the CancelKeyPress
and hadn't realised that I need to supress the default behavior by setting ConsoleCancelEventArgs.Cancel
to true
. Now that I know this, I have a working solution:
Console.CancelKeyPress += OnCancel;
bool cancelRequested = false;
while (!cancelRequested)
{
var now = DateTime.Now;
Console.Write(now);
Console.Write(" ");
Console.Write(now.Millisecond);
Console.CursorLeft = 0; // Overwrite the same line
}
Console.WriteLine();
Console.WriteLine("Goodbye");
void OnCancel(object? sender, ConsoleCancelEventArgs e)
{
e.Cancel = true; // Stops cancel key press from terminating the app
cancelRequested = true; // Signal the main loop the request to cancel
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论