Multithreaded Testing...
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!