views:

70

answers:

2

I have a C# application that has to constantly read from a program; sometimes there is a chance it will not find what it needs, which will throw an exception. This is a limitation of the program it has to read from.

This frequently causes the program to lock up as it tries to poll. So I solved it by spawning the 'polling' off into a separate thread. However watching the debugger, the thread is created and destroyed each time. I am uncertain if this is typical or not; but my question is, is this good practice, or am I using the threading for the wrong purpose?

ProgramReader
{ 
  static Thread oThread;
  public static void Read( Program program )
  {
    // check to see if the program exists
    if ( false )
      oThread = new ThreadStart(program.Poll);
    if(oThread != null || !oThread.IsAlive )
      oThread.Start();
  }
}

This is my general pseudocode. It runs every 10 seconds or so. Is this a huge hit to performance? The operation it performs is relatively small and lightweight; just repetitive.

A: 

Either create a thread which waits and sleeps, or use the ThreadPool, which sounds like the thing to do for your task.

Lucero
How can I stop the thread from being destroyed after each poll? That is more my problem. I am a little lost in that respect. Threading is very new to me in general so I'm a bit nervous about getting into it.
Stacey
You can achieve this by using a loop inside the thread procedure, so that you in fact only start the thread once and let it run and sleep (sleeping uses no CPU cycles and very little resources overall).
Lucero
+3  A: 

A Thread can't be "restarted", which is why you're seeing what you're seeing in the debugger. It's normal behaviour, but I'm worried about two issues here:

  1. You say specifically that the Program will throw an exception sometimes, but you never actually catch it. Unhandled exceptions on background threads will bring down your entire process.

  2. You spawn threads regardless of circumstances. It's not clear whether or not Program.Poll is actually thread-safe (my guess is no), and even if it is, you may not want to flood the system with these requests.

A better design would probably be something like:

private AutoResetEvent polledEvent = new AutoResetEvent(true);

public void Read(Program program)
{
    polledEvent.WaitOne();
    ThreadPool.QueueUserWorkItem(s => 
    {
        try
        {
            program.Poll();
        }
        catch (PollingException ex)
        {
            // Handle the exception
        }
        polledEvent.Set();
    });
}

This will solve both of the above problems by handling any exceptions as well as throttling the number of polling requests that can happen at the same time. It also reuses threads by using the ThreadPool.

If the Poll method is really thread-safe and you're OK with several requests being queued up, change the AutoResetEvent to a Semaphore and initialize it with the actual number of requests you want to happen simultaneously.

One final note: If this is happening in a Windows Forms, Windows Service or WPF application, I'd recommend using a BackgroundWorker instead of rolling your own threading code. Most of the work is already done for you there, you just need to write your polling loop inside the DoWork event handler.

Aaronaught
If I have another thread that has to wait for this one to find something to complete, is there any way to facilitate that?
Stacey
Eh.. it isn't really happening in Windows Forms. I mean the program that will use it is a Forms program; But the actual stuff going on is pInvoke. Would a BackgroundWorker still be the best option?
Stacey
@Stacey: The `AutoResetEvent` and `ManualResetEvent` are the tools you would use to do that. However, waiting synchronously for this entire operation to complete brings you back to your original problem of causing the main program to "lock up." I suspect you may want an async callback; if you can use the `BackgroundWorker`, this becomes *very* easy, you just add an event handler for `RunWorkerCompleted`. If not, it's a little more complicated, you'll have to do some of your own synchronization.
Aaronaught
@Stacey: Answering the second comment, yes, I believe that a `BackgroundWorker` would still be the best option if your application is a Windows Forms app. Using that component, you won't need to write any threading code whatsoever. It doesn't matter where the calls are ultimately headed; all you're trying to do is prevent blocking the UI while the process is running.
Aaronaught
+1 in general, but really, BackgroundWorker is often overlooked when it does the job most of the time for bits like this.
Jim Leonardo
I think this is everything I need. Thank you very much; this is very enlightening.
Stacey