实现线程队列

时间:2012-02-10 20:42:56

标签: c# wpf multithreading

考虑这个例子: 当用户点击按钮时, ClassA 会快速触发OnUserInteraction个事件10次。 ClassB 附加到此事件,并在其事件处理程序中触发 ClassC 的Render方法。在Render方法中执行AxisAngleRotation3D,但每个动画都持续1秒。

在这种情况下,几乎所有10个AxisAngleRotation3D动画都会同时执行,但我希望它们能够一个接一个地执行。据我了解线程,我可能不得不在ClassB中实现一个线程队列,其中Completed的{​​{1}}事件表示允许下一个事件触发......?< / p>

这是正确的,我该如何实现?

2 个答案:

答案 0 :(得分:3)

ClassB可以将事件添加到队列中,然后一次渲染一个(可能使用计时器从队列中读取)。

答案 1 :(得分:3)

拥有一个任务队列。简而言之,拥有ConcurrentQueue<Func<bool>>字段或类似字段,并根据需要向其添加任务。然后让你的任务执行线程弹出Func<bool>委托队列并调用它们。如果他们返回真实,他们就完成了。如果它们返回false,则将它们添加回队列,因为它们当时无法完成。

以下是一个例子:

using System;
using System.Collections.Concurrent;
using System.Threading;

namespace Example
{
    public class TaskScheduler : IDisposable
    {
        public const int IDLE_DELAY = 100;

        private ConcurrentQueue<Func<bool>> PendingTasks;
        private Thread ExecuterThread;
        private volatile bool _IsDisposed;

        public bool IsDisposed
        {
            get { return _IsDisposed; }
        }

        public void EnqueueTask(Func<bool> task)
        {
            PendingTasks.Enqueue(task);
        }

        public void Start()
        {
            CheckDisposed();

            if (ExecuterThread != null)
            {
                throw new InvalidOperationException("The task scheduler is alreader running.");
            }

            ExecuterThread = new Thread(Run);
            ExecuterThread.IsBackground = true;
            ExecuterThread.Start();
        }

        private void CheckDisposed()
        {
            if (_IsDisposed)
            {
                throw new ObjectDisposedException("TaskScheduler");
            }
        }

        private void Run()
        {
            while (!_IsDisposed)
            {
                if (PendingTasks.IsEmpty)
                {
                    Thread.Sleep(IDLE_DELAY);
                    continue;
                }

                Func<bool> task;
                while (!PendingTasks.TryDequeue(out task))
                {
                    Thread.Sleep(0);
                }

                if (!task.Invoke())
                {
                    PendingTasks.Enqueue(task);
                }
            }
        }

        public void Dispose()
        {
            CheckDisposed();
            _IsDisposed = true;
        }
    }
}