[C#] Console-Application crasht bei SetConsoleCtrlHandler und Console.ReadLine()

05/06/2015 15:01 pvpDealer#1
Servus!
Ich habe derzeit ein komisches Problem:
Ich schreibe eine Konsolenanwendung und möchte, bevor die Konsole geschlossen wird, den Speicher aufräumen (manuelles GC).

Code:
private delegate bool ConsoleEventDelegate(int eventType);

[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool SetConsoleCtrlHandler(ConsoleEventDelegate callback, bool add);
		
private static Dictionary<string, IRunable> runablesDict;
private static List<Thread> runablesThreadList;

public static void Main(string[] args)
{
	runablesDict = new Dictionary<string, IRunable>();
	runablesThreadList = new List<Thread>();

	SetConsoleCtrlHandler(new ConsoleEventDelegate(ConsoleEventCallback), true);

	InitializeRunables();
	RunRunables(args);
}

private static void InitializeRunables()
{
	runablesDict.Add("market_fetcher", new MarketFetcher());
}

private static void RunRunables(string[] arguments)
{
	foreach (KeyValuePair<string, IRunable> runableEntry in runablesDict)
	{
		Thread runableThread = new Thread(() =>
		{
			runableEntry.Value.Run(runableEntry.Key, arguments);
		});

		runablesThreadList.Add(runableThread);

		runableThread.Start();
	}
}

private static void UnloadRunables()
{
	foreach (KeyValuePair<string, IRunable> runableEntry in runablesDict)
		runableEntry.Value.Dispose();
	
	foreach (Thread runableThread in runablesThreadList)
		KillThread(runableThread);   
}

private static bool ConsoleEventCallback(int eventType)
{
	if (eventType == 2)
		UnloadRunables();

	return false;
}

[SecurityPermissionAttribute(SecurityAction.Demand, ControlThread = true)]
private static void KillThread(Thread thread)
{
	thread.Abort();
}
Das funktioniert soweit auch sehr gut, aber: Sobald die Konsole gerade auf eine Eingabe wartet (bspw. durch Console.ReadLine()) und ich die Konsole schließe (egal ob per Ctrl+C oder per Close-Button) crashed die Anwendung. Als Unhandled Exception erhalte ich eine NullReferenceException - ich kann den Code aber nicht debuggen, da das Programm crashed, bevor der Eventcallback aufgerufen wird.

Kann natürlich auch sein, dass ich komplett daneben liege, und das garnichts mit der Eingabe zu tun hat - das Problemm tritt aber eben nur bei dieser Situation auf.

Ich hoffe, ihr habt eine Idee, wie ich das lösen kann :)
05/06/2015 18:23 qqdev#2
Wieso möchtest du vor dem Beenden den GC anschmeißen? Wenn das Programm beendet wird, dann wird automatisch jeglicher Speicher wieder freigegeben, der vom Prozess reserviert wurde.
05/06/2015 19:39 Mostey#3
Quote:
Originally Posted by qqdev View Post
Wieso möchtest du vor dem Beenden den GC anschmeißen? Wenn das Programm beendet wird, dann wird automatisch jeglicher Speicher wieder freigegeben, der vom Prozess reserviert wurde.
Vermutlich um seine Ressourcen noch sauber freizugeben und laufende Threads zu beenden, ohne dass gewisse Daten verloren gehen. Gut, aus dem Beispiel oben geht das nicht wirklich hervor aber ich würde einfach mal schätzen, dass sowas gedacht war. Wenn es jedoch wirklich nur bei einem einfachen Thread.Abort bleibt und Value.Dispose nichts serialisiert (oder ähnliches), kann man das OS auch einfach alles killen lassen, das macht dann auch keinen Sinn es selbst zu tun.

Er hat das Problem übrigens anscheinend schon behoben (siehe cross-post auf stackoverflow). Auch wenn ich nicht glaube, dass genau das zur Problemlösung geführt hat.
05/07/2015 02:42 pvpDealer#4
Habe nach einigem Suchen dann das gefunden: [Only registered and activated users can see links. Click Here To Register...]

Genau das hat das Problem behoben.

Bzgl. dem manuellem GC:
Ich habe einige Klassen die das IDisposable Interface implementieren; beim Schließen rufe ich dann Dispose() der erwähnten Klassen auf. Dabei logge ich mich bspw. bei EPvP aus (epvpapi) - falls ihr eine Idee habt, wie man das besser lösen kann, immer her damit :b
05/11/2015 10:19 MrSm!th#5
Du kannst Dispose im Destruktor der Klasse aufrufen, dann wird das ganze automatisch beim anstoßen des GCs erledigt.