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());
}
}