0

我正在创建一个自动完成控件,该控件会随着用户键入文本而更新。每次用户键入一个键时,都会触发一个新线程以过滤结果。结果来自网络并且很多,因此过滤大约需要 1 分钟。这与我所拥有的类似:

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

如您所见,如果我在哪里快速键入“Hello”,那么将创建 5 个线程,其中 4 个必须等待第一个线程完成。一旦该线程完成,下一个线程将继续执行,依此类推。

如果存在 4 个线程等待执行,我只想执行最后一个。线程也以随机顺序进入锁。我怎么能确定哪个是最后一个。如果一个新线程触发并且一个线程当前正在执行,也许我可以以某种方式取消该线程,这样顺序将始终正确。我该如何实现该算法?


编辑

这是我制定的:

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

我可以将该类用作:

        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.
4

2 回答 2

2

除了 mellamokb 的评论,听起来你根本不想要一个线程——你想要一个线程,有一个下一个要执行的任务”——如果已经有一个任务要执行,它会被新的一。本质上就像一个生产者/消费者队列,但只有一个被覆盖的“槽”。

于 2012-04-20T20:35:24.087 回答
0

在 TPL 数据流中,这正是BroadcastBlock它所做的:它始终只记住发布到它的最后一个项目。如果将其链接到ActionBlock容量限制为 1 的容量,则该ActionBlock操作将按照您想要的方式执行。

尽管仅为此使用 TPL 数据流可能没有多大意义。

于 2012-04-20T20:47:04.110 回答