Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
On multiple occasions, I've found myself in need of a design pattern to allow a single thread to do some work, while other threads block. I'm not getting into the details about how this environment comes about, or what I'm exactly doing , but let me define the problem space:
- I've got a method that gets repeatedly executed by 20 threads concurrently. Let's call it, "IterationRun".
- Within this method, I want a single thread to execute another method (it's a void method, so it can be used as an Action.)
- While the above "DoWork" method is executing, I want all other threads to block, so they don't exit IterationRun, thus entering it again.
The following design seems to do a good job of satisfying the above criteria. I'm open to critique, by the way. Also, this is half pseudo-code. The driver that executes IterationRun, sets up threads, and such is left out. Have a look at the DoWorkOnASingleThread method.
namespace PseudoishCode
{
using System;
using System.Threading;
public class PseudoishCodeExample
{
// Counter used to identify individual threads
private static int threadCount = 0;
private static ManualResetEvent preWorkBlock;
private static ManualResetEvent postWorkBlock;
private static int runningIterationCount = 0;
private static object thisLock = new object();
// Total threads that will be executing
private int threads = 10;
private int threadId = 0;
// Set up done once per process - multiple threads not yet created.
public void ProcessSetup()
{
preWorkBlock = new ManualResetEvent(true);
postWorkBlock = new ManualResetEvent(false);
// Insert other code here that should get executed before ThreadSetup and IterationRun
// . . .
}
// This method is called by each thread. After all threads call this, they start executing IterationRun
public void ThreadSetup()
{
this.threadId = Interlocked.Increment(ref threadCount);
}
public void IterationRun()
{
// Insert code here that all threads should execute.
// . . .
this.DoWorkOnASingleThread(new Action(this.DoWork));
// Insert code here that all threads should execute.
// . . .
}
private void DoWork()
{
// Do something here
}
// Takes care of all synchronization necessary to make sure a single thread does the action while blocking all other threads.
private void DoWorkOnASingleThread(Action work)
{
preWorkBlock.WaitOne();
lock (thisLock)
{
if (++runningIterationCount == this.threads)
{
runningIterationCount = 0;
// Single thread can take action here.
work.Invoke();
preWorkBlock.Reset();
postWorkBlock.Set();
}
}
postWorkBlock.WaitOne();
lock (thisLock)
{
if (++runningIterationCount == this.threads)
{
runningIterationCount = 0;
postWorkBlock.Reset();
preWorkBlock.Set();
}
}
}
}
}
Note - Keep in mind, this pattern is intended for use in a stress testing environment. I don't really see much use for it outside of that, but if you know of a production scenario where this is useful, I'd be interested to hear about it!