Freigeben über


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:

 

  1. I've got a method that gets repeatedly executed by 20 threads concurrently.  Let's call it, "IterationRun".
  2. 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.) 
  3. 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!