using System; using System.Threading; using System.Collections.Concurrent; namespace RageCoop.Core { /// /// A worker that constantly execute jobs in a background thread. /// public class Worker:IDisposable { private SemaphoreSlim _semaphoreSlim; private Thread _workerThread; private bool _stopping=false; /// /// Name of the worker /// public string Name { get; set; } /// /// Whether this worker is busy executing job(s). /// public bool IsBusy { get;private set; } internal Worker(string name,Logger logger,int maxJobs = Int32.MaxValue) { Name = name; _semaphoreSlim = new SemaphoreSlim(0,maxJobs); _workerThread=new Thread(() => { while (!_stopping) { IsBusy=false; _semaphoreSlim.Wait(); if(Jobs.TryDequeue(out var job)) { IsBusy=true; try { job.Invoke(); } catch (Exception ex) { logger.Error("Error occurred when executing queued job:"); logger.Error(ex); } } else { throw new InvalidOperationException("Hmm... that's unexpected."); } } IsBusy=false; }); _workerThread.Start(); } /// /// Queue a job to be executed /// /// public void QueueJob(Action work) { Jobs.Enqueue(work); _semaphoreSlim.Release(); } /// /// Finish current job and stop the worker. /// public void Stop() { _stopping=true; QueueJob(() => { }); if (_workerThread.IsAlive) { _workerThread.Join(); } } /// /// Finish current job and stop the worker. /// public void Dispose() { Stop(); _semaphoreSlim.Dispose(); } private ConcurrentQueue Jobs=new ConcurrentQueue(); } }