Thursday, November 11, 2004
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).
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).
// declarationsprivate 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 logicpublic 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 logicpublic 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 jobspublic void MoreInput(object someInput){
Console.WriteLine("More Input: " + someInput.ToString());
lock (mQue.SyncRoot){
mQue.Enqueue(someInput);}
mWaitEvent.Set();}
// process jobspublic void OnMyOwnThread(){
while (mStayAlive){if (mWaitEvent.WaitOne()){
mWaitEvent.Reset();while (mQue.Count > 0){ //Whether we do the looping depends
//on the specifics of DoWorkif (!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/inputif (queObj != null){
Console.WriteLine("Processing: " + queObj.ToString());
Thread.Sleep(300);//LONG PROCESSING
Console.WriteLine("Processed " + Environment.TickCount.ToString());
}
}
Labels: dot NET general
Copyright © Daniel Moth


