Producer consumer C # Concurrent Design Based on Asynchronous queue,
The original code is based on the concurrency design of the concurrent queue version <producer consumer C # Concurrent Design Based on blocking queue> <. net parallel programming-4. implement High-Performance asynchronous queue> modified. The previous articles also detail other concurrent implementation solutions and implementations. Directly to the code:
Public class MyAsyncQueue <T> {// whether the queue is Processing data private int isProcessing; // a thread is Processing data private const int Processing = 1; // no thread processes data private const int UnProcessing = 0; // whether the queue is available private volatile bool enabled = true; // The Consumer thread private Task currentTask; // The Consumer thread processes the event public event Action <T> ProcessItemFunction; // public event EventHandler <EventArgs <Exception> ProcessException; // the concurrent queue private ConcurrentQueu E <T> queue; // number of consumers private int _ internalTaskCount; // stores the consumer queue List <Task> tasks = new List <Task> (); public MyAsyncQueue () {_ internalTaskCount = 3; queue = new ConcurrentQueue <T> (); Start ();} public int Count {get {return queue. count ;}/// enable the listening Thread private void Start () {Thread process_Thread = new Thread (PorcessItem); process_Thread.IsBackground = true; process_Thread.Start ();} // producer produces pub Lic void Enqueue (T items) {if (items = null) {throw new ArgumentException ("items");} queue. enqueue (items); DataAdded () ;}// notify the consumer thread to process private void DataAdded () {if (enabled) {if (! IsProcessingItem () {// enable consumer consumption queue ProcessRangeItem () ;}}// determine whether a thread in the queue is processing private bool IsProcessingItem () {return! (Interlocked. compareExchange (ref isProcessing, Processing, UnProcessing) = 0);} private void ProcessRangeItem () {for (int I = 0; I <_ internalTaskCount; I ++) {currentTask = Task. factory. startNew () => ProcessItemLoop (); tasks. add (currentTask) ;}}// the consumer processes the event private void ProcessItemLoop () {Console. writeLine ("Id of the Task being executed: {0}", Task. currentId); // The queue is empty and the queue is unavailable if (! Enabled & queue. isEmpty) {Interlocked. exchange (ref isProcessing, 0); return;} // whether the number of threads processed is smaller than the current maximum number of tasks // if (Thread. volatileRead (ref runingCore) <= this. maxTaskCount) // {T publishFrame; while (enabled) {if (queue. tryDequeue (out publishFrame) {try {// consumer Processing Event ProcessItemFunction (publishFrame);} catch (Exception ex) {OnProcessException (ex);} else {Console. writeLine ("thread Id {0} failed to get the queue, jump out of the loop", Task. CurrentId); break ;}}} /// <summary> /// scheduled processing thread call function /// mainly monitors the status of threads not being sent and processed when the queue is in progress. /// </summary> private void porcessItem (object state) {int sleepCount = 0; int sleepTime = 1000; while (enabled) {// if the queue is empty, the sleep time is determined based on the number of cycles if (queue. isEmpty) {// The Task consumer has consumed the data in the queue .... cancel consumer thread if (tasks. count = _ internalTaskCount) {Flush ();} if (sleepCount = 0) {sleepTime = 1000;} else if (sleepCount <= 3) {sleepT Ime = 1000*3;} else {sleepTime = 1000*50;} sleepCount ++; Thread. sleep (sleepTime);} else {// determines whether a thread in the queue is processing if (enabled & Interlocked. compareExchange (ref isProcessing, Processing, UnProcessing) = 0) {if (! Queue. isEmpty) {currentTask = Task. factory. startNew (ProcessItemLoop); tasks. add (currentTask);} else {// The queue is empty and Interlocked has been obtained. exchange (ref isProcessing, 0) ;}sleepcount = 0; sleepTime = 1000 ;}}// update and disable the public void Flush () {Stop () consumer (); foreach (var t in tasks) {if (t! = Null) {t. Wait (); Console. WriteLine ("Task completed") ;}// the consumer has not consumed the while (! Queue. isEmpty) {try {T publishFrame; if (queue. tryDequeue (out publishFrame) {ProcessItemFunction (publishFrame) ;}} catch (Exception ex) {OnProcessException (ex) ;}} currentTask = null; tasks. clear ();} public void Stop () {this. enabled = false;} private void OnProcessException (System. exception ex) {var tempException = ProcessException; Interlocked. compareExchange (ref ProcessException, null, Null); if (tempException! = Null) {ProcessException (ex, new EventArgs <Exception> (ex ));}}}
Call code:
Class ComInfo {public int ComId {get; set;} public DateTime Date {get; set ;}} class Program {static MyAsyncQueue <ComInfo> queue = new MyAsyncQueue <ComInfo> (); static void Main (string [] args) {Console. writeLine ("START ======"); queue. processItemFunction + = A; queue. processException + = C; // new EventHandler <EventArgs <Exception> (C); ComInfo info = new ComInfo (); for (int I = 1; I <50; I ++) {Task. factory. startNew (param) =>{ info = new ComInfo (); info. comId = int. parse (param. toString (); info. date = DateTime. now. date; queue. enqueue (info) ;}, I) ;} Console. writeLine ("End ======"); Console. readKey ();} static void A (ComInfo info) {Console. writeLine (info. comId + "=" + queue. count);} static void C (object ex, EventArgs <Exception> args) {Console. writeLine ("error ");}}
The concurrent series should be finished in this way. You can sort it back into a directory and check it easily.