Thu, November 11, 2004, 08:09 AM under
dotNET
Sometimes we write code that uses polling. A brief example of that is some method/routine that runs on a timer (e.g. every 5 seconds), reads new entries from a file/database and performs some operation based on the input - and repeates this cycle until we stop the timer.
Although there are valid scenarios for taking the approach described above, there are others where it is a sub-optimal solution. For example, if you need to know as soon as there is a new entry to process, then there is no point waiting for your timer's tick; conversly, if there are no new items to process then there is no point running the function. A similar (equally not good) alternative is instead of running a timer to make the thread sleep for a while.
So in those case where the 2 aforementioned similar solutions are not the best, what is the correct way? Use a thread! The following code shows you an example of how. Note that I use this technique with the Compact Framework so, for example, we need the extra boolean to tell the thread to kill itself/exit since the CF 1.0 threads are missing many properties that could help (e.g. IsBackground, Abort etc).
// declarations
private Thread mSendNextThread; // worker thread
private bool mStayAlive; // for controlling the thread termination
private Queue mQue; // buffer of jobs
private ManualResetEvent mWaitEvent;// signal the thread to wake up
// Initialisation logic
public void Start(){ Console.WriteLine("*********"); Console.WriteLine("Start"); mQue = new Queue();
mWaitEvent = new ManualResetEvent(false);
mStayAlive = true;
mSendNextThread = new Thread(new ThreadStart(OnMyOwnThread));
mSendNextThread.Start();
}
// Tear down logic
public void Stop(){ Console.WriteLine("Stop request"); lock (mQue.SyncRoot){ mQue.Clear();
// kill the thread
mWaitEvent.Reset();
Thread.Sleep(10);
mStayAlive = false;
mWaitEvent.Set();
Thread.Sleep(10);
mSendNextThread = null;
}
Console.WriteLine("Stopped"); }
// queue more jobs
public void MoreInput(object someInput){ Console.WriteLine("More Input: " + someInput.ToString()); lock (mQue.SyncRoot){ mQue.Enqueue(someInput);
}
mWaitEvent.Set();
}
// process jobs
public void OnMyOwnThread(){ while (mStayAlive){ if (mWaitEvent.WaitOne()){
mWaitEvent.Reset();
while (mQue.Count > 0){ //Whether we do the looping depends //on the specifics of DoWork
if (!mStayAlive){ break;
}
this.DoWork2();
mWaitEvent.Reset();
}
}
}
Console.WriteLine("Thread exiting"); }
private void DoWork2(){ object queObj = null;
lock (mQue.SyncRoot){ if (mQue.Count > 0){ queObj = mQue.Dequeue();
}
}
// do some long processing with this job/input
if (queObj != null){ Console.WriteLine("Processing: " + queObj.ToString()); Thread.Sleep(300);//LONG PROCESSING
Console.WriteLine("Processed " + Environment.TickCount.ToString()); }
}