Skip to content
This repository has been archived by the owner on Jan 13, 2023. It is now read-only.

Threads

Christian Junk edited this page Jan 19, 2022 · 1 revision

Threads are complex, and Rhino Commons is here to try to help. The library contains several interesting classes with regards to threads: RhinoThreadPool, ThreadSafeQueue, CountdownLatch

RhinoThreadPool

The RhinoThreadPool allows you to:

  • Cancel pending work or abort executing threads safely
  • Wait for work in the thread pool to be completed
  • Events for starting and finishing work items

Basic usage is similar to the usual thread pool:

RhinoThreadPool.QueueUserWorkItem(new WaitCallback(MyCallback), myState);

But once you started on that, you can do more interesting things with it.

WorkItem workItem = RhinoThreadPool.QueueUserWorkItem(new WaitCallback(MyCallback), myState);
// at a later time
workItem.Cancelled = true;//will prevent it from running if it is not already running
// or this, which allows you to get its state 
WorkItemStatus status = RhinoThreadPool.Cancel(workItem, false);
// and optionally abort the work item execution if needed
WorkItemStatus status = RhinoThreadPool.Cancel(workItem, true);

You can also register work and wait for it:

for(int i=0;i<100;i++)
{
   RhinoThreadPool.QueueUserWorkItem(new WaitCallback(Foo), i);
}
RhinoThreadPool.WaitForAllThreadsToFinish();

Events:

When work item begins to run:

RhinoThreadPool.WorkStarted += delegate(WorkItem item)
{
   Console.WriteLine(item.State+" started");
}

When work item finishes to run, including abnormally:

RhinoThreadPool.WorkFinished += delegate(WorkItem item)
{
   Console.WriteLine(item.State+" started");
}

Exceptions:

Important: RhinoThreadPool doesn't try to catch exceptions, if a user work item callback has thrown an exception, it will be propagate to the default .NET handling of unhandled thread exception, and will usually terminate the application.

Thread Safe Queue

As the name implies, it allows to Enqueue() and Dequeue() in a thread safe manner. Trying to Dequeue from an empty queue will block, until there is data to return. To call the queue without blocking, use TryDequeue()

Countdown Latch

A simple lock implementation that allows a producer to wait for a set of consumer to finish their work, here is a simple test that demonstrate its usage:

 [Test]
 public void WaitForEventToRun()
 {
     int count = 5000;
     CountdownLatch countdown = new CountdownLatch(count);
     bool[">count">](https://web.archive.org/web/20120619180408/http://ayende.com/wiki/Rhino+Commons+-+Threads.ashx%5d+done+%3d+new+bool%5bcount.ashx "] done = new bool<a class=") done = new bool\[count;
     for (int i = 0; i < count; i++)
     {
         int j = i;
         ThreadPool.QueueUserWorkItem(delegate
         {
             done[j](https://web.archive.org/web/20120619180408/http://ayende.com/wiki/Rhino+Commons+-+Threads.ashxj.ashx "j") = true;
             countdown.Set();
         });
     }
     bool result = countdown.WaitOne();
     Assert.IsTrue(result);
     for (int i = 0; i < count; i++)
     {
         Assert.IsTrue(done[i](https://web.archive.org/web/20120619180408/http://ayende.com/wiki/Rhino+Commons+-+Threads.ashxi.ashx "i"), "{0} was not set to true", i);
     }
 }
Clone this wiki locally