There is a program that, upon execution, should return 0 or 1 in case of success / failure. Operations can be interrupted by a shortcut key. When interrupted, the value of true should fall into the global variable stopState, but it remains false, respectively, Main does not respond correctly. Help me to understand

Here is the code:

Program.cs:

using System; using System.IO; using System.Threading; namespace ConsoleThreadTest { class Program { // основной поток static void MainThread(string typeJob,string fileInput, string fileOut) { Zip zip = new Zip(); zip.Action(typeJob, fileInput, fileOut); } // фоновый поток static void listenKey(Thread th) { ConsoleKeyInfo cki; Console.TreatControlCAsInput = true; while (true) { cki = Console.ReadKey(); if ((cki.Modifiers & ConsoleModifiers.Control) != 0 && cki.Key == ConsoleKey.C) { stopState = true; Console.WriteLine("StopState = {0}", stopState); Console.WriteLine("Программа остановлена вручную"); Console.WriteLine("Целевой файл удалён"); th.Abort(); break; } } } private static void ActionJob(string typeJob, string fileInput, string fileOut) { if (FileCheck.CheckPath(fileInput, fileOut)) { if (FileCheck.FileExistCheck(fileInput, fileOut)) { Thread actionThread = new Thread(() => MainThread(typeJob, fileInput, fileOut)); Thread listenKeyThread = new Thread(() => listenKey(actionThread)); listenKeyThread.IsBackground = true; actionThread.Start(); listenKeyThread.Start(); } } } public static bool stopState = false; static int Main(string[] args) { //stopState = false; if (args.Length == 3) { ActionJob(args[0], args[1], args[2]); } else { Console.WriteLine("Парметры запуска заданы неверно"); } if ((!File.Exists(args[2]) && (stopState == false))) { return 0; } else return 1; } } } 

FileCheck.cs:

 using System; using System.IO; using System.Text.RegularExpressions; namespace ConsoleThreadTest { class FileCheck { public static bool CheckPath(string fileInput, string fileOut) { // паттерн для проверки второго и третьего параметров string pattern = @"([a-zA-Z]:(\/|\\))((\w+(\/|\\))*(\w+(.\w+)?))"; if (Regex.IsMatch(fileInput, pattern)) { if (Regex.IsMatch(fileOut, pattern)) { return (true); } else { Console.WriteLine("третий параметр не является путём к файлу"); Console.ReadLine(); return false; } } else { Console.WriteLine("второй параметр не является путём к файлу"); Console.ReadLine(); return false; } } public static bool FileExistCheck(string fileInput, string fileOut) { if (File.Exists(fileInput)) { if (!File.Exists(fileOut)) { return true; } else { Console.WriteLine("Имя целевого файла уже используется"); return false; } } else { Console.WriteLine("Указанного файла не существует"); return false; } } } } 

Zip.cs:

 using System; using System.IO; using System.IO.Compression; using System.Threading; namespace ConsoleThreadTest { class Zip { public void Action(string typeJob, string fileInput, string fileOut) { Console.WriteLine("Ctrl + c - для отмены..."); if (FileCheck.FileExistCheck(fileInput,fileOut)) { using (FileStream sourceStream = new FileStream(fileInput, FileMode.Open)) { using (FileStream targetStream = File.Create(fileOut)) { switch (typeJob) { case "compress": Console.WriteLine("Упаковка файла: {0} в архив {1}", fileInput, fileOut); using (GZipStream compressionStream = new GZipStream(targetStream, CompressionMode.Compress)) { try { sourceStream.CopyTo(compressionStream); break; } catch (ThreadAbortException) { if (sourceStream != null && compressionStream != null && targetStream != null) { sourceStream.Close(); compressionStream.Close(); targetStream.Close(); } File.Delete(fileOut); break; } } case "decompress": Console.WriteLine("Распаковка архива: {0} в файл {1}", fileInput, fileOut); using (System.IO.Compression.GZipStream decompressionStream = new GZipStream(sourceStream, CompressionMode.Decompress)) { try { decompressionStream.CopyTo(targetStream); break; } catch (ThreadAbortException) { if (sourceStream != null && decompressionStream != null && targetStream != null) { sourceStream.Close(); decompressionStream.Close(); targetStream.Close(); } File.Delete(fileOut); break; } catch (InvalidDataException) { Console.WriteLine("Возможно путь к архиву указывает на файл иного типа"); File.Delete(fileOut); break; } } default: Console.WriteLine("Первый аргумент указан неверно"); Console.WriteLine("Следует выбрать compress или decompress"); File.Delete(fileOut); break; } } } } } } } 

I checked the answer: If you add listenKey (Join), the program will not end until this same join happens, but it does not have to happen.

When Ctrl + c is triggered, stopState still considers false, added to listenKey when triggered stopState = true; however, in the end, the program returns the same 0;

Updated the code to the current

  • stopState = false is an assignment, false is always returned, therefore the expression in if (smth) && (false) will always be false - Grundy
  • I do not understand anything. If the code is current, then where is .Join() ? Find the line with listenKeyThread.Start(); and then below (after .Start() ) add listenKeyThread.Join(); - Artyom Okonechnikov
  • There, listenKey.Join is not needed, I eventually changed the public boolean variable to a public class variable, and used it as a trigger, it all worked out with a bang. And yes, wait for the end of the main function before checking it helped me actionThread.join () - Garrus_En

1 answer 1

Probably, you wanted to use the operator == but the assignment turned out:

 (stopState = false) 

Also, you start the listenKeyThread.Start() stream and you do not listenKeyThread.Start() for it to stop, but already check whether it is alive or not (it is alive and it is spinning a cycle). If you need to wait for the thread to execute, then call the next line, listenKeyThread.Join() then everything will work as you expect.


Of course, I also want to note that to solve your problem, you absolutely do not need the listenKeyThread thread. What is happening now? The listenKeyThread thread listenKeyThread and at the same time, the main Main thread waits for the completion of this thread and does nothing useful. In your case, it would be logical to transfer the code of this thread to Main , and forget the listenKeyThread as a listenKeyThread dream.

  • You start the listenKeyThread.Start() stream and do not listenKeyThread.Start() for it to stop, but already check whether it is alive or not (it is alive and it is spinning a cycle). If you need to wait for the thread to execute, then call the next line, listenKeyThread.Join() then everything will work as you expect. - Artyom Okonechnikov
  • one
    @ArtyomOkonechnikov, postpone your comment in response - Grundy