基于ConcurrentQueue<T>的简单工作队列

  队列,是一种先进先出(FIFO)的集合,队列的一个作用就是可以对需要并发访问公共资源的请求进行排队。

  这里利用ConcurrentQueue<T>队列来模拟一个场景。场景的本意就是,提供一个公共资源,然后用多线程模拟多个用户请求更改这个公共资源,这里使用队列,对每一个请求进行排队。

  ConcurrentQueue<T>是.NET fromework4.5中的一个线程安全的队列,这里主要用到该类中的Enqueue(入队)以及TryDequeue(出队)方法。

  废话不多说,下面开始贴代码。

  1、SimpleWorkQueue类,是对ConcurrentQueue<T>类的简单封装,里面设置了一个线程专门负责处理入队的请求,在Enqueue方法里面,每次入队都会判断该线程是否工作,如不,则启动工作线程去处理请求,

如果队列中的请求已经处理完毕,则杀死工作线程。这里没有用的死循环,是出于效率的考虑。

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Ye.SimpleQueue
{
    public delegate void WorkItem();
    public class SimpleWorkQueue
    {
        private bool isWork = false;
        private Thread workThread;
        private ConcurrentQueue<WorkItem> queue;

        public SimpleWorkQueue()
        {
            queue = new ConcurrentQueue<WorkItem>();
        }

        /// <summary>
        /// 入队
        /// </summary>
        /// <param name="workItem"></param>
        public void Enqueue(WorkItem workItem)
        {
            queue.Enqueue(workItem);
            //通知线程开始处理工作,这里做了并发处理
            if (!isWork)
            {
                Monitor.Enter(this);
                if (!isWork)
                {
                    isWork = true;
                    Resume();
                }
                Monitor.Exit(this);
            }
        }

        /// <summary>
        /// 出队
        /// </summary>
        /// <returns></returns>
        public WorkItem Dequeue()
        {
            WorkItem result = null;
            if(!queue.TryDequeue(out result))
                Kill();
            return result;
        }

        /// <summary>
        /// 开始工作
        /// </summary>
        private void DoWork()
        {
            if (!isWork || queue.Count <= 0)
                Kill();
            else
            {
                WorkItem workItem;
                //循环执行队列中的工作
                while ((workItem = Dequeue()) != null)
                {
                    workItem();
                }
                isWork = false;
            }
        }

        /// <summary>
        /// 杀死work线程
        /// </summary>
        private void Kill()
        {
            if (workThread.IsAlive)
            {
                try
                {
                    workThread.Abort();
                }
                catch (Exception ex)
                {
                    
                }
                finally
                {
                    isWork = false;
                }
            }
        }

        /// <summary>
        /// 重新启动工作线程
        /// </summary>
        private void Resume()
        {
            if (workThread == null || !workThread.IsAlive)
            {
                workThread = new Thread(DoWork);
                workThread.Start();
            }
        }
    }
}

 

  2、启动程序例子,这里使用了Parallel类的Invoke方法,该方法会尽可能地保证每个action并行执行,注意,是尽可能,所有测试结果会有偏差是肯定的,因此,本例子只能作为一个参考,真正需要完善的地方还有很多= =||。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Ye.SimpleQueue;

namespace ConsoleApp
{
    public class Program
    {
        private static int index = 200;
        static void Main(string[] args)
        {
            SimpleWorkQueue queue = new SimpleWorkQueue();
            Action action1 = () => { queue.Enqueue(AddWork); };
            Action action2 = () => { queue.Enqueue(DoWork); };
            Action action3 = () => { queue.Enqueue(AddWork); };
            Action action4 = () => { queue.Enqueue(DoWork); };
            Parallel.Invoke(action1, action2, action3, action4);
            Console.ReadKey();
        }

        private static void DoWork()
        {
            for (int i = 0; i < 10; i++)
            {
                index = index - 1;
                Console.WriteLine(index);
            }
        }

        private static void AddWork()
        {
            for(int i=0;i<5;i++)
            {
                index = index + 1;
                Console.WriteLine(index);
            }
        }
    }
}

  3、下面是运行结果:

 

  从运行结果可以看出来,入队的顺序是AddWork,DoWork,AddWork,DoWork,所以结果是,先增加5,然后减少10,再增加5,然后减少10。

但这里有一个坑爹的地方,我多次运行的结果都是一样的!结论么,要么就是Parallel类的Invoke方法太坑爹(只是尽可能地保证并行),要么就是我人品不行= =b,

有兴趣的朋友可以多试几次,或者可以以其他方法来做并发测试~

 

  由于本人水平有限,如有发现错误,恳请各位大神不吝赐教^_^#,谢谢~

posted @ 2015-10-20 09:00  尋找一個證明  阅读(568)  评论(0)    收藏  举报