Skip to content

Instantly share code, notes, and snippets.

@joshpeterson
Created August 15, 2010 12:59
Show Gist options
  • Save joshpeterson/525467 to your computer and use it in GitHub Desktop.
Save joshpeterson/525467 to your computer and use it in GitHub Desktop.
This code queues some work for a background thread, then waits for that work to complete.
// #FixMyCode
// This code queues some work for a background thread, then waits for that work to complete.
// Can you make it more correct, more elegant, faster, or just plain better? If so, please do!
// Fork this Gist and tweet me the result @joshuampeterson.
using System;
using System.Collections.Generic;
using System.Threading;
namespace WaitForBackgroundThread
{
class Program
{
private static int sum;
static void Main(string[] args)
{
AutoResetEvent stopBackgroundThread = new AutoResetEvent(false);
Queue<WorkerInformation> queue = new Queue<WorkerInformation>();
object queueLock = new object();
int gaussianSum = (1000 * 1001)/2;
BackgroundThread consumer = new BackgroundThread(stopBackgroundThread, queue, queueLock);
SentinelArgs sentinelArgs = new SentinelArgs();
lock (queueLock)
{
for (int i = 1; i <= 1000; ++i)
{
queue.Enqueue(new WorkerInformation(AddToSum, null, new AddToSumArgs(i)));
}
queue.Enqueue(new WorkerInformation(SignalSentinel, null, sentinelArgs));
}
sentinelArgs.Sentinel.WaitOne();
Console.WriteLine("Gauss's sum: {0}", gaussianSum);
Console.WriteLine("Background thread's sum: {0}", sum);
Console.WriteLine("They {0}!", gaussianSum == sum ? "match" : "do not match");
stopBackgroundThread.Set();
}
class AddToSumArgs : EventArgs
{
private int numberToAdd;
public AddToSumArgs(int numberToAdd)
{
this.numberToAdd = numberToAdd;
}
public int NumberToAdd { get { return this.numberToAdd; } }
}
private static void AddToSum(object sender, EventArgs arguments)
{
sum += ((AddToSumArgs)arguments).NumberToAdd;
}
class SentinelArgs : EventArgs
{
private AutoResetEvent sentinel = new AutoResetEvent(false);
public AutoResetEvent Sentinel { get { return this.sentinel; } }
}
private static void SignalSentinel(object sender, EventArgs arguments)
{
((SentinelArgs)arguments).Sentinel.Set();
}
delegate void Worker(object sender, EventArgs arguments);
class WorkerInformation
{
private Worker worker;
private object sender;
private EventArgs arguments;
public WorkerInformation(Worker worker, object sender, EventArgs arguments)
{
this.worker = worker;
this.sender = sender;
this.arguments = arguments;
}
public Worker Worker { get { return this.worker; } }
public object Sender { get { return this.sender; } }
public EventArgs Arguments { get { return this.arguments; } }
}
class BackgroundThread
{
private AutoResetEvent stopBackgroundThread;
private Queue<WorkerInformation> queue;
private object queueLock;
public BackgroundThread(AutoResetEvent stopBackgroundThread, Queue<WorkerInformation> queue,
object queueLock)
{
this.stopBackgroundThread = stopBackgroundThread;
this.queue = queue;
this.queueLock = queueLock;
Thread consumer = new Thread(this.Run);
consumer.Start();
}
private void Run()
{
while (!this.stopBackgroundThread.WaitOne(10))
{
WorkerInformation workerInformation = null;
lock (this.queueLock)
{
if (this.queue.Count > 0)
{
workerInformation = this.queue.Dequeue();
}
}
if (workerInformation != null)
{
workerInformation.Worker(workerInformation.Sender, workerInformation.Arguments);
}
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment