基于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,
有兴趣的朋友可以多试几次,或者可以以其他方法来做并发测试~
由于本人水平有限,如有发现错误,恳请各位大神不吝赐教^_^#,谢谢~

浙公网安备 33010602011771号