|
…
using System.Threading;
namespace Chevron.UpstreamArchitecture.Services.Whatever
{
class ConsoleApp
{
static void Main(string[] args)
{
DoStuffSimultaneously doit = new DoStuffSimultaneously();
// Call our method, passing in the data we want it to work on in parallel.
string stringsAppendedInMulitpleThreads = doit.DoStuff(new string[] { "one ", "two ", "three " });
// Spit out the results
Console.WriteLine(stringsAppendedInMulitpleThreads);
}
}
class DoStuffSimultaneously
{
string _response = string.Empty; // Common object the threads update with their work.
AutoResetEvent[] _waitAllEvents; // Array of objects to wait upon.
/// <summary>
/// This method takes in a set of work and calls multiple threads for each unit of work.
/// </summary>
/// <param name="whatToDo">An array of strings to be appended together, each by a different thread.</param>
/// <returns>The result of all the multiple threads' work.</returns>
public string DoStuff(string[] whatToDo)
{
// Create an array of objects to wait upon; we need one per thread
_waitAllEvents = new AutoResetEvent[whatToDo.Count];
// Populate array of waiting objects, one for each work item
for (int i = 0; i < whatToDo.Count; i++)
_waitAllEvents[i] = new AutoResetEvent(false);
// Create callback on the method we want to do the work
WaitCallback callBack = new WaitCallback(CallSlowWebServiceInNewThread);
// Iterate through all our work items, creating a thread for each and passing in the data
// we want the thread to work on and the event we are waiting on as a state object (a Pair in this example - could be any object)
for(int i=0; i < whatToDo.Count; i++)
ThreadPool.QueueUserWorkItem(callBack, new Pair(whatToDo[i], _waitAllEvents[i]));
// Wait until all our threads have signaled their wait object is done.
if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA)
{
// WaitAll for multiple handles on an STA thread is not supported.
// ...so wait on each handle individually.
foreach (WaitHandle myWaitHandle in _waitAllEvents)
WaitHandle.WaitAny(new WaitHandle[] { myWaitHandle });
}
else
{
WaitHandle.WaitAll(_waitAllEvents);
}
// When we get here then all our threads have done their work, so we can return our result object.
return _response;
}
/// <summary>
/// This method calls our slow web service does some work in a separate thread.
/// </summary>
/// <param name="state">A Pair object containing a string as the work item, and a AutoResetEvent to set when we are done.</param>
static void CallSlowWebServiceInNewThread(object state)
{
// Get the work for this thread out of the pair
Pair pair = state as Pair;
// Get an instance of our Slow Web Service
Slow slowWebservice = new Slow();
// Call slow Web Service using our work item (be careful of race conditions here; so lock work item)
lock (_response)
{
// Get something from our Slow WebService
_response += slowWebservice.DoSomething(pair.First);
}
// Get our wait item out of the pair
AutoResetEvent autoResetEvent = pair.Second as AutoResetEvent;
// Set our wait item to indicate we are done here.
autoResetEvent.Set();
}
}
} |