I am creating an auto-complete control that updates as the user types text. Every time the user types a key a new thread fires in order to filter the results. The results come over the network and are a lot therefore it takes about 1 minute to filter. This is something similar of what I have:
object _lock = new object();
volatile static bool isThreadRunning=false ;
private void textBox1_TextChanged(object sender, TextChangedEventArgs e)
{
var text = textBox1.Text.ToUpper();
ThreadPool.QueueUserWorkItem((o) =>
{
lock (_lock) // avoid multiple threads to be running at the same time
{
isThreadRunning = true;
// do work in here
isThreadRunning=false;
}
},text);
}
So as you can see if I where to quickly type “Hello” then 5 threads will be created and 4 of them will have to wait for the first one to finish. Once that thread finishes the next one will continue to execute and so on.
If there exists 4 threads waiting to execute I will like to only execute the last one. Also the threads enter the lock in random order. How could I determine which is the last one. If a new thread fires and a thread is currently executing maybe I could cancel that thread somehow and that way the order will always be correct. How can I implement that algorithm?
EDIT
This is what I have worked out:
class DoWorkOnce
{
static object _lock = new object();
static Stack<Action> Work = new Stack<Action>();
public static void Add(Action task)
{
Work.Push(task);
DoSomeWork();
}
private static void DoSomeWork()
{
Task.Factory.StartNew(() =>
{
lock (_lock) // ensure that the following block of code is only executed at once
{
if (Work.Count == 0) // if there is no items in the stack return
return;
Work.Pop()(); // get the last item in the stack and execute it
// remove the bottom of the stack by poping everything exept the top item
Action temp=null;
if(Work.Count>0)
temp = Work.Pop();
while (Work.Count > 0)
Work.Pop();
if (temp != null)
Work.Push(temp);
}
});
}
}
and I can use that class as:
string[] simulationOfTyping = new string[] { "H", "He", "Hel", "Hell", "Hello", "Hello ", "Hello W", "Hello Wo", "Hello Wor", "Hello Worl", "Hello World" };
// simulate user typing
foreach(var text in simulationOfTyping)
{
Thread.Sleep(50);
DoWorkOnce.Add(() =>
{
Console.WriteLine(text);
Thread.Sleep(1000);
});
}
// the last item should execute always.
Aside from mellamokb’s comment, it sounds like you don’t really want a thread pool at all – you want a single thread, with a single “next task to execute” – where if there’s already a task to execute, it’s overwritten by the new one. Essentially like a producer/consumer queue, but with only one “slot” which is overwritten.