简体   繁体   中英

Is there a better way to keep a console app from returning besides using while?

I have a small C# console application that runs some code then checks for a specific executable to complete.

The problem I had (I don't normally write console applications) is when I get to the code that checks for the termination of an executable, my Main() returns and the console application closes. The code which checks for the executable is running thru a Timer(). For the moment I've kept the Main alive by adding while(true) { } and that seems to be working except that it (obviously) eats up a ton of excess CPU time.

Is there a better way to keep the Main() function from returning?

    static Timer tmrCheck = new Timer();
    static void Main(string[] args)
    {
        Initialize();
        while (true) ; // If this line is removed, the application will close after
                       // the last line of Initialize() is run.
    }

    static void Initialize()
    {
        tmrCheck.Elapsed += tmrCheck_Elapsed;
        tmrCheck.Interval = 10000;
        tmrCheck.Enabled = true; // After this line, Initialize returns to Main()
    }

    static void tmrCheck_Elapsed(object sender, ElapsedEventArgs e)
    {
        // Get a list of processes
        // Check to see if process has exited
        // If so, run *this* code then exit console application.
        // If not, keep timer running.
    }

If you just need to wait until the launched process exits.
This could be written in your Timer.Elapsed event

Process[] p = Process.GetProcessesByName("yourprocessname");
if(p.Length > 0) 
{
    p[0].WaitForExit();
    Console.WriteLine("Finish");    
}
else
{ 
    // Do other things
}

EDIT
Looks that this could be tried. I am not sure about threading issues here so waiting for someone more expert that points to the weakness of this approach

static Timer tmrCheck = new Timer();
static bool waiting = false;
static void Main(string[] args)
{
    Initialize();
    Console.WriteLine("Press enter to stop the processing....");
    Console.ReadLine();
    tmrCheck.Stop();
}

static void Initialize()
{
    tmrCheck.Elapsed += (s, e) =>
    {
        Console.WriteLine("Timer event");
        if(!waiting)
        {
            Process[] p = Process.GetProcessesByName("yourprocessname");
            if(p.Length > 0)
            {
                waiting = true;
                Console.WriteLine("Waiting for exit");
                p[0].WaitForExit();
                Timer t = s as Timer;
                t.Stop();
                Console.WriteLine("Press enter to end application");

            }
        }
        else
        {
            // other processing activities
        }
    };
    tmrCheck.Interval = 10000;
    tmrCheck.Enabled = true; 
}

Try: Thread.Sleep(1); in your while loop. Even sleeping one millisecond should save you a lot of CPU cycles.

Hope that helps

Well you can use as others mentioned Thead.Sleep and rewrite your code like this:

static void Main(string[] args)
{
   while (true) 
   {
        // Get a list of processes
        // Check to see if process has exited
        // If so, run *this* code then exit console application.
        // If not, keep timer running.
       Thread.Sleep(10000); // Wait 10s and retry your previous actions
   }
}

Another suggestion (i sometimes using for thread cancellation option)

static void Main(string[] args)
{
   int timeout = 10;
   int timeoutCount = 10;
   while (true) 
   {
      //Here you can check cancellation flag

      if(timeout == timeoutCount)
      {
        timeoutCount = 0;
        // Get a list of processes
        // Check to see if process has exited
        // If so, run *this* code then exit console application.
        // If not, keep timer running.
      }
      Thread.Sleep(1000); // Wait 1s and retry your previous actions
      timeoutCount++;
   }
}

You could try something like this:

static void Main(string[] args)
{
    var procs = Process.GetProcessesByName("LINQPad").ToList();

    if (procs.Any())
    {
        procs.ForEach(p => p.EnableRaisingEvents = true);
        procs.ForEach(p => p.Exited += OnExited);
        procs.ForEach(p => p.WaitForExit());
    }

    Console.WriteLine("All processes exited...");
    Console.ReadKey();
}

private static void OnExited(object sender, EventArgs eventArgs)
{
    Console.WriteLine("Process Has Exited");
}

You didn't mention if you're monitoring multiple processes or not, but you could just remove the .ForEach statements and do the same logic for a single process, if not. Also, i'm not sure if Console.ReadKey() is what you had in mind for keeping the process from exiting... Or if you only need to keep it from exiting until the process(es) have closed.

You don't say what version of the .Net framework you're using or if the application launches the process, but... If you're using 4.0 or higher and the app does launch the process, then you can use a Task ( System.Threading.Tasks ) to launch the process and Task.Wait.

using System.Threading.Tasks;
static Timer tmrCheck = new Timer();
Task doWork;
static void Main(string[] args)
{
    Initialize();
     /// do more work if required
    doWork.Wait();

}

static void Initialize()
{
    tmrCheck.Elapsed += tmrCheck_Elapsed;
    tmrCheck.Interval = 10000;
    tmrCheck.Enabled = true; // After this line, Initialize returns to Main()
   // Initialize() seems the place to do start up, but this code could move to where ever the proocess is started.
    doWork = Task.Factory.StartNew(() =>
            {
                startTheProcessHere();
            }
        );
}

Pluralsight has a good course: Introduction to Async and Parallel Programming in .NET 4

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM