C# 콘솔 앱에서 Ctrl+C(SIGINT)를 어떻게 트랩합니까?
종료하기 전에 정리 작업을 수행할 수 있도록 C# 콘솔 응용 프로그램에 +를 C트랩할 수 있습니다.이것을 하는 가장 좋은 방법은 무엇입니까?
콘솔.CancelKeyPress 이벤트가 이에 사용됩니다.사용 방법은 다음과 같습니다.
public static void Main(string[] args)
{
Console.CancelKeyPress += delegate {
// call methods to clean up
};
while (true) {}
}
사용자가 +를 C누르면 대리인의 코드가 실행되고 프로그램이 종료됩니다.이렇게 하면 필요한 메서드를 호출하여 정리를 수행할 수 있습니다.대리자가 실행된 후에는 코드가 없습니다.
이것으로 해결되지 않는 다른 상황들이 있습니다.예를 들어 프로그램이 현재 즉시 중지할 수 없는 중요한 계산을 수행하고 있는 경우입니다.이 경우 계산이 완료된 후 프로그램을 종료하도록 지시하는 것이 올바른 전략일 수 있습니다.다음 코드는 이를 구현하는 방법의 예를 보여줍니다.
class MainClass
{
private static bool keepRunning = true;
public static void Main(string[] args)
{
Console.CancelKeyPress += delegate(object? sender, ConsoleCancelEventArgs e) {
e.Cancel = true;
MainClass.keepRunning = false;
};
while (MainClass.keepRunning) {
// Do your work in here, in small chunks.
// If you literally just want to wait until Ctrl+C,
// not doing anything, see the answer using set-reset events.
}
Console.WriteLine("exited gracefully");
}
}
이 코드와 첫 번째 예제의 차이점은e.Canceltrue로 설정되어 있습니다. 즉, 대리자 이후에도 실행이 계속됩니다.실행되면 프로그램은 사용자가 +C를 누를 때까지 기다립니다.그런 일이 발생합니다.keepRunningvariable은 값을 변경하여 while 루프를 종료합니다.이것은 프로그램을 정상적으로 종료하는 방법입니다.
MSDN 참조:
코드 샘플이 포함된 기사:
Ctrl-C 및 를 누릅니다.NET 콘솔 응용 프로그램
조나스의 답변에 추가하고 싶습니다.위에서 회전boolCPU 활용률이 100%에 이르고 C+를 기다리는 동안 아무것도 하지 않고 많은 에너지를 낭비합니다.
더 나은 해결책은 다음을 사용하는 것입니다.ManualResetEvent+C를 실제로 "기다려"는 것:
static void Main(string[] args) {
var exitEvent = new ManualResetEvent(false);
Console.CancelKeyPress += (sender, eventArgs) => {
eventArgs.Cancel = true;
exitEvent.Set();
};
var server = new MyServer(); // example
server.Run();
exitEvent.WaitOne();
server.Stop();
}
다음은 완전한 작업 예제입니다. 빈 C# 콘솔 프로젝트에 붙여넣기:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
namespace TestTrapCtrlC {
public class Program {
static bool exitSystem = false;
#region Trap application termination
[DllImport("Kernel32")]
private static extern bool SetConsoleCtrlHandler(EventHandler handler, bool add);
private delegate bool EventHandler(CtrlType sig);
static EventHandler _handler;
enum CtrlType {
CTRL_C_EVENT = 0,
CTRL_BREAK_EVENT = 1,
CTRL_CLOSE_EVENT = 2,
CTRL_LOGOFF_EVENT = 5,
CTRL_SHUTDOWN_EVENT = 6
}
private static bool Handler(CtrlType sig) {
Console.WriteLine("Exiting system due to external CTRL-C, or process kill, or shutdown");
//do your cleanup here
Thread.Sleep(5000); //simulate some cleanup delay
Console.WriteLine("Cleanup complete");
//allow main to run off
exitSystem = true;
//shutdown right away so there are no lingering threads
Environment.Exit(-1);
return true;
}
#endregion
static void Main(string[] args) {
// Some biolerplate to react to close window event, CTRL-C, kill, etc
_handler += new EventHandler(Handler);
SetConsoleCtrlHandler(_handler, true);
//start your multi threaded program here
Program p = new Program();
p.Start();
//hold the console so it doesn’t run off the end
while (!exitSystem) {
Thread.Sleep(500);
}
}
public void Start() {
// start a thread and start doing some processing
Console.WriteLine("Thread started, processing..");
}
}
}
이 질문은 다음과 매우 유사합니다.
제가 이 문제를 해결하고 Ctrl-C뿐만 아니라 X를 치는 사용자를 처리한 방법은 다음과 같습니다.수동 재설정 이벤트를 사용합니다.이렇게 하면 메인 스레드가 절전 모드로 전환되어 종료 또는 정리를 기다리는 동안 CPU가 다른 스레드를 처리할 수 있습니다.참고: 종료 완료 이벤트를 메인 끝에 설정해야 합니다.그렇지 않으면 애플리케이션을 종료하는 동안 OS가 시간 초과되어 불필요한 종료 대기 시간이 발생합니다.
namespace CancelSample
{
using System;
using System.Threading;
using System.Runtime.InteropServices;
internal class Program
{
/// <summary>
/// Adds or removes an application-defined HandlerRoutine function from the list of handler functions for the calling process
/// </summary>
/// <param name="handler">A pointer to the application-defined HandlerRoutine function to be added or removed. This parameter can be NULL.</param>
/// <param name="add">If this parameter is TRUE, the handler is added; if it is FALSE, the handler is removed.</param>
/// <returns>If the function succeeds, the return value is true.</returns>
[DllImport("Kernel32")]
private static extern bool SetConsoleCtrlHandler(ConsoleCloseHandler handler, bool add);
/// <summary>
/// The console close handler delegate.
/// </summary>
/// <param name="closeReason">
/// The close reason.
/// </param>
/// <returns>
/// True if cleanup is complete, false to run other registered close handlers.
/// </returns>
private delegate bool ConsoleCloseHandler(int closeReason);
/// <summary>
/// Event set when the process is terminated.
/// </summary>
private static readonly ManualResetEvent TerminationRequestedEvent;
/// <summary>
/// Event set when the process terminates.
/// </summary>
private static readonly ManualResetEvent TerminationCompletedEvent;
/// <summary>
/// Static constructor
/// </summary>
static Program()
{
// Do this initialization here to avoid polluting Main() with it
// also this is a great place to initialize multiple static
// variables.
TerminationRequestedEvent = new ManualResetEvent(false);
TerminationCompletedEvent = new ManualResetEvent(false);
SetConsoleCtrlHandler(OnConsoleCloseEvent, true);
}
/// <summary>
/// The main console entry point.
/// </summary>
/// <param name="args">The commandline arguments.</param>
private static void Main(string[] args)
{
// Wait for the termination event
while (!TerminationRequestedEvent.WaitOne(0))
{
// Something to do while waiting
Console.WriteLine("Work");
}
// Sleep until termination
TerminationRequestedEvent.WaitOne();
// Print a message which represents the operation
Console.WriteLine("Cleanup");
// Set this to terminate immediately (if not set, the OS will
// eventually kill the process)
TerminationCompletedEvent.Set();
}
/// <summary>
/// Method called when the user presses Ctrl-C
/// </summary>
/// <param name="reason">The close reason</param>
private static bool OnConsoleCloseEvent(int reason)
{
// Signal termination
TerminationRequestedEvent.Set();
// Wait for cleanup
TerminationCompletedEvent.WaitOne();
// Don't run other handlers, just exit.
return true;
}
}
}
SIGTERM 및 +:C
CancellationTokenSource ctSource = new();
CancellationToken ct = ctSource.Token;
void ExitHandler()
{
// You can add any arbitrary global clean up
Console.WriteLine("Exiting...");
ctSource.Cancel();
}
// Assign exit handler to be called when the process is terminated
// or the user hits CTRL+C
AppDomain.CurrentDomain.ProcessExit += (sender, args) => ExitHandler();
Console.CancelKeyPress += (sender, args) => ExitHandler();
// Then you can use the cancellation token to check for exit:
Console.WriteLine("Ready to gracefully shut down!");
while (!ct.IsCancellationRequested)
{
Console.WriteLine($"Exit not detected, waiting another 10s.");
Task.Delay(10000, ct).Wait(ct);
}
나가기 전에 정리 작업을 수행할 수 있습니다.이것을 하는 가장 좋은 방법은 진정한 목표입니다: 함정 출구, 당신만의 물건을 만드는 것입니다.그리고 그것을 올바르게 만들지 않는 것보다 더 나은 대답.왜냐하면 Ctrl+C는 앱을 종료하는 많은 방법 중 하나일 뿐이기 때문입니다.
dotnet c#의 내용 - 이른바 취소 토큰 전달 대상Host.RunAsync(ct)신호 는 Windows의 경우는 Windows의 경우입니다.
private static readonly CancellationTokenSource cts = new CancellationTokenSource();
public static int Main(string[] args)
{
// For gracefull shutdown, trap unload event
AppDomain.CurrentDomain.ProcessExit += (sender, e) =>
{
cts.Cancel();
exitEvent.Wait();
};
Console.CancelKeyPress += (sender, e) =>
{
cts.Cancel();
exitEvent.Wait();
};
host.RunAsync(cts);
Console.WriteLine("Shutting down");
exitEvent.Set();
return 0;
}
...
Console.TreatControlCAsInput = true;나를 위해 일했습니다.
언급URL : https://stackoverflow.com/questions/177856/how-do-i-trap-ctrlc-sigint-in-a-c-sharp-console-app
'IT' 카테고리의 다른 글
| 판다 다중 지수 - 열을 사용할 때 2단계를 선택하는 방법은 무엇입니까? (0) | 2023.05.13 |
|---|---|
| 수업에서 스토리보드를 프로그래밍 방식으로 로드하려면 어떻게 해야 합니까? (0) | 2023.05.13 |
| 불변 문화와 순서 문자열 비교의 차이 (0) | 2023.05.13 |
| 사용자 또는 관리자가 응용프로그램 사용에 동의하지 않았습니다 - 이 사용자 및 리소스에 대한 대화형 권한 부여 요청을 보냅니다. (0) | 2023.05.13 |
| 각도 - 모든 요청에 대한 헤더 설정 (0) | 2023.05.13 |