Browse Source

Remove InvalidOperationException and use Task.Delay with CancellationTokenSource.

BDisp 1 năm trước cách đây
mục cha
commit
f749eef8e9
2 tập tin đã thay đổi với 52 bổ sung42 xóa
  1. 51 41
      Terminal.Gui/ConsoleDrivers/NetDriver.cs
  2. 1 1
      Terminal.Gui/Core/Application.cs

+ 51 - 41
Terminal.Gui/ConsoleDrivers/NetDriver.cs

@@ -113,7 +113,9 @@ namespace Terminal.Gui {
 		ConsoleDriver consoleDriver;
 		volatile ConsoleKeyInfo [] cki = null;
 		static volatile bool isEscSeq;
-		bool stopTasks;
+
+		internal CancellationTokenSource TokenSource = new CancellationTokenSource ();
+
 #if PROCESS_REQUEST
 		bool neededProcessRequest;
 #endif
@@ -125,21 +127,13 @@ namespace Terminal.Gui {
 				throw new ArgumentNullException ("Console driver instance must be provided.");
 			}
 			this.consoleDriver = consoleDriver;
-			Task.Run (ProcessInputResultQueue);
-			Task.Run (CheckWinChange);
-		}
-
-		internal void StopTasks ()
-		{
-			stopTasks = true;
+			Task.Run (ProcessInputResultQueue, TokenSource.Token);
+			Task.Run (CheckWinChange, TokenSource.Token);
 		}
 
 		public InputResult? ReadConsoleInput ()
 		{
-			while (true) {
-				if (stopTasks) {
-					return null;
-				}
+			while (!TokenSource.IsCancellationRequested) {
 				waitForStart.Set ();
 				winChange.Set ();
 
@@ -154,11 +148,13 @@ namespace Terminal.Gui {
 					return inputResultQueue.Dequeue ();
 				}
 			}
+
+			return null;
 		}
 
 		void ProcessInputResultQueue ()
 		{
-			while (true) {
+			while (!TokenSource.IsCancellationRequested) {
 				waitForStart.Wait ();
 				waitForStart.Reset ();
 
@@ -176,12 +172,19 @@ namespace Terminal.Gui {
 			ConsoleModifiers mod = 0;
 			ConsoleKeyInfo newConsoleKeyInfo = default;
 
-			while (true) {
-				ConsoleKeyInfo consoleKeyInfo;
+			while (!TokenSource.IsCancellationRequested) {
+				ConsoleKeyInfo consoleKeyInfo = default;
 
 				try {
-					consoleKeyInfo = Console.ReadKey (true);
-				} catch (InvalidOperationException ex) {
+					if (Console.KeyAvailable) {
+						consoleKeyInfo = Console.ReadKey (true);
+					} else {
+						Task.Delay (100, TokenSource.Token).Wait (TokenSource.Token);
+						if (Console.KeyAvailable) {
+							consoleKeyInfo = Console.ReadKey (true);
+						}
+					}
+				} catch (OperationCanceledException) {
 
 					return;
 				}
@@ -209,18 +212,19 @@ namespace Terminal.Gui {
 					}
 					break;
 				} else {
-					GetConsoleInputType (consoleKeyInfo);
-					break;
+					if (consoleKeyInfo != default) {
+						GetConsoleInputType (consoleKeyInfo);
+						break;
+					}
 				}
+
+				TokenSource.Token.ThrowIfCancellationRequested ();
 			}
 		}
 
 		void CheckWinChange ()
 		{
-			while (true) {
-				if (stopTasks) {
-					return;
-				}
+			while (!TokenSource.IsCancellationRequested) {
 				winChange.Wait ();
 				winChange.Reset ();
 				WaitWinChange ();
@@ -230,13 +234,16 @@ namespace Terminal.Gui {
 
 		void WaitWinChange ()
 		{
-			while (true) {
-				// Wait for a while then check if screen has changed sizes
-				Task.Delay (500).Wait ();
+			while (!TokenSource.IsCancellationRequested) {
+				try {
+					// Wait for a while then check if screen has changed sizes
+					Task.Delay (500, TokenSource.Token).Wait (TokenSource.Token);
+
+				} catch (OperationCanceledException) {
 
-				if (stopTasks) {
 					return;
 				}
+
 				int buffHeight, buffWidth;
 				if (((NetDriver)consoleDriver).IsWinPlatform) {
 					buffHeight = Math.Max (Console.BufferHeight, 0);
@@ -699,7 +706,7 @@ namespace Terminal.Gui {
 
 		public override void End ()
 		{
-			mainLoop.netEvents.StopTasks ();
+			mainLoop.Dispose ();
 
 			if (IsWinPlatform) {
 				NetWinConsole.Cleanup ();
@@ -1455,7 +1462,7 @@ namespace Terminal.Gui {
 	/// <remarks>
 	/// This implementation is used for NetDriver.
 	/// </remarks>
-	internal class NetMainLoop : IMainLoopDriver {
+	internal class NetMainLoop : IMainLoopDriver, IDisposable {
 		ManualResetEventSlim keyReady = new ManualResetEventSlim (false);
 		ManualResetEventSlim waitForProbe = new ManualResetEventSlim (false);
 		Queue<NetEvents.InputResult?> inputResult = new Queue<NetEvents.InputResult?> ();
@@ -1485,27 +1492,25 @@ namespace Terminal.Gui {
 
 		void NetInputHandler ()
 		{
-			while (true) {
+			while (!tokenSource.IsCancellationRequested) {
 				waitForProbe.Wait ();
 				waitForProbe.Reset ();
 				if (inputResult.Count == 0) {
 					inputResult.Enqueue (netEvents.ReadConsoleInput ());
 				}
-				try {
-					while (inputResult.Peek () == null) {
-						inputResult.Dequeue ();
-					}
-					if (inputResult.Count > 0) {
-						keyReady.Set ();
-					}
-				} catch (InvalidOperationException) { }
+				while (inputResult.Count > 0 && inputResult.Peek () == null) {
+					inputResult.Dequeue ();
+				}
+				if (inputResult.Count > 0) {
+					keyReady.Set ();
+				}
 			}
 		}
 
 		void IMainLoopDriver.Setup (MainLoop mainLoop)
 		{
 			this.mainLoop = mainLoop;
-			Task.Run (NetInputHandler);
+			Task.Run (NetInputHandler, tokenSource.Token);
 		}
 
 		void IMainLoopDriver.Wakeup ()
@@ -1535,8 +1540,7 @@ namespace Terminal.Gui {
 				return inputResult.Count > 0 || CheckTimers (wait, out _);
 			}
 
-			tokenSource.Dispose ();
-			tokenSource = new CancellationTokenSource ();
+			tokenSource.Token.ThrowIfCancellationRequested ();
 			return true;
 		}
 
@@ -1569,5 +1573,11 @@ namespace Terminal.Gui {
 				ProcessInput?.Invoke (inputResult.Dequeue ().Value);
 			}
 		}
+
+		public void Dispose ()
+		{
+			tokenSource.Cancel ();
+			netEvents.TokenSource.Cancel ();
+		}
 	}
 }

+ 1 - 1
Terminal.Gui/Core/Application.cs

@@ -1133,9 +1133,9 @@ namespace Terminal.Gui {
 
 			// BUGBUG: MdiTop is not cleared here, but it should be?
 
-			MainLoop = null;
 			Driver?.End ();
 			Driver = null;
+			MainLoop = null;
 			Iteration = null;
 			RootMouseEvent = null;
 			RootKeyEvent = null;