0

I put together a console/forms hybrid program, and to achieve the behavior I was looking for I had to "run" the console in a thread, and then launch the dashboard with another.

I used BackgroundWorker for this. Essentially in the Main method I start the console background worker which in its DoWork block performs a normal while loop to keep a console going. Repetitively checking for input from the console and passing it along to it corresponding action.

while (true && !Program.Shutdown)
{
    String consoleInput = "";

    consoleInput = Program.ReadFromConsole();

    if (String.IsNullOrWhiteSpace(consoleInput))
        continue;

    try
    {
        Program.Shell(consoleInput);
    }
    catch (Exception ex)
    {
        Program.WriteToConsole(ex.Message);
    }
}

After the background worker for starting the console is called i.e. ConsoleBackgroundWorker.RunWorkerAsync() I call a method which performs a loading sequence.

This loading sequence CAN call the second background worker which internally launches the dashboard on a separate thread.

Now the problem I faced was the loop at the end of the load sequence. This loop prevents everything from shutting down until both of the background workers have completed (the forms closed or the console sent a command to shutdown)

while (ConsoleBackgroundWorker != null && DashboardBackgroundWorker != null)
{
    /* I'm not sure of how else to fix this. But 
     * this corrects the high CPU usage reported 
     * in the Task Manager. */
    System.Threading.Thread.Sleep(10);
}

The problem was CPU usage, it was constantly sitting at 30% and this is without the line you see above System.Threading.Thread.Sleep(10)

My question is, is this ok? and if not what solution do I have? I noticed this did correct the issue, the CPU now rides at 0% when the application is not doing anything. I also haven't seen any performance changes either. But it has not really been "pushed" yet so I couldn't say for sure on the latter observation.

Stephen Kennedy
  • 20,585
  • 22
  • 95
  • 108
David Carrigan
  • 751
  • 1
  • 8
  • 21
  • 2
    Use [Synchronization Primitives](https://msdn.microsoft.com/en-us/library/ms228964(v=vs.110).aspx) and avoid using that loops – EZI Jul 11 '15 at 00:51
  • So could the [Barrier Class](https://msdn.microsoft.com/en-us/library/system.threading.barrier(v=vs.110).aspx) help me? This is all new material for me so that might take me a bit to read and comb through. – David Carrigan Jul 11 '15 at 01:05
  • Use Task Parallel Library, you do not need to worry about each and every synchronization primitives – Mrinal Kamboj Jul 11 '15 at 02:13

1 Answers1

6

Instead of polling (checking every 10ms, as you've done) the "better" (or at least less CPU intensive) solution would be to use some kind of wait-functions. You could use a ManualResetEvent maybe, or any of the other synchronization objects available in the System.Threading namespace. Depends on what you need. Then you can just call .Wait() on that object and it will block the thread (0% actual CPU usage) until some kind of signal arrives from another thread.

Vilx-
  • 104,512
  • 87
  • 279
  • 422
  • Thanks this sounds about right but will take me a bit to implement. I'll report back and mark as the answer when I make some progress. – David Carrigan Jul 11 '15 at 01:41
  • That was quick and worked beautifully! Essentially I declared a global [`ManualResetEvent`](https://msdn.microsoft.com/en-us/library/system.threading.manualresetevent(v=vs.110).aspx) which I call `.WaitOne()` where the polling loop originally was. Then from where the shutdown originates I call `.Set()` and all falls through as it should. Thanks again. – David Carrigan Jul 11 '15 at 01:52
  • Event Synchronization is fine, but why not use TPL , to wait on a task, that would be much more elegant solution and it does run on thread Pool threads – Mrinal Kamboj Jul 11 '15 at 02:12
  • @MrinalKamboj - True, but it sounds like the OP already has a lot in place. This was a smaller change, I think. – Vilx- Jul 11 '15 at 12:09
  • @ Vilx agreed for a quick change this would be appropriate – Mrinal Kamboj Jul 11 '15 at 15:07
  • Yes @Vilx- you are correct. I have over 20 thousand lines of pure mechanical code in play. You're solution was far easier then I was original expecting. When we are in a grace period I will take note and definitely consider some of these more appropriate implementations of multi-threading practices and available objects. – David Carrigan Jul 11 '15 at 17:17