Return values from ThreadPool.QueueUserWorkItem in a chain of 3 threads for Silverlight. 

Basically what I’d like to demonstrate here is how to chain 3 ThreadPool.QueueUserWorkItem calls where each thread return a value that is required by the following thread in a chain, this is also useful when working with MEF since you are working with only one instance of your module, you need to be careful to not use global variables too much, especially when multithreading, so all the results are being pass as return values.

This return value should not be global because these calls came from another thread waiting for the chains to complete.

Here is the code:

First we need to create the link between the threads:

public class CalcParams

{

    public int CallID;

    public ManualResetEvent ManualReset;

    public Action<int,ManualResetEvent,int> CallbackDone;

}

 

The main thread for the example creates an array of ManualResetEvents, and then executes all the chains in parallel and wait for them to complete.

private void LayoutRoot_Loaded(object sender, RoutedEventArgs e)

{

    ThreadPool.QueueUserWorkItem((obj) =>

    {

        ManualResetEvent[] finishcalc = new ManualResetEvent[] 

        { 

            new ManualResetEvent(false), 

            new ManualResetEvent(false), 

            new ManualResetEvent(false), 

            new ManualResetEvent(false), 

            new ManualResetEvent(false), 

            new ManualResetEvent(false

        };

        DoCalculation(rand.Next(10), rand.Next(10), 1, finishcalc[0]);

        DoCalculation(rand.Next(10), rand.Next(10), 2, finishcalc[1]);

        DoCalculation(rand.Next(10), rand.Next(10), 3, finishcalc[2]);

        DoCalculation(rand.Next(10), rand.Next(10), 4, finishcalc[3]);

        DoCalculation(rand.Next(10), rand.Next(10), 5, finishcalc[4]);

        DoCalculation(rand.Next(10), rand.Next(10), 6, finishcalc[5]);

 

        if (WaitHandle.WaitAll(finishcalc))

        {

            AddTextAsync(“DoCalculation Finish \n”);

        }

    });

}

 

DoCalculation contains the 3 level deep calculations where all the threads are connected using the class link to pass the parameters:

void DoCalculation( int number1,int number2,int callid, ManualResetEvent calcdone)

{

//Display the values used by the calculation in the corresponding Call ID

AddTextAsync(string.Format(“The values for Callid {0} are {1} and {2}\n”,callid , number1,number2));

ThreadPool.QueueUserWorkItem((obj) =>

{

    //in this case the calculation is the sum of two numbers, it could be any task like

    //call a webservice for the first thread level it is not required to pass the 

    //parameters as part of the link, as for the following levels.so im using the method 

    //parameters directly

    int result = number1 + number2;

    //after calculation is complete that the obj parameter as cast as the link

    CalcParams localparams = (obj as CalcParams);                

    //here Im using the values passed by the Link class to execute the action in 

    //the chain with the method parameters

    localparams.CallbackDone(result,localparams.ManualReset,localparams.CallID);

}, new CalcParams()

{

    //these are the method parameters being pass to the thread through the link class

    ManualReset = calcdone,

    CallID = callid,

    //this is the second level callback 

    CallbackDone = (r, m, i) =>

    {                    

        //in the second level I execute another thread passing again the values using 

        //the link class

        ThreadPool.QueueUserWorkItem((obj) =>

        {

            //this time im calculating the sqrt of the previous result

            int sqrt = r*r;

            CalcParams localparams = (obj as CalcParams);

            //im calling the 3rd level Callback passing the result and the original 

            //parameters as well

            localparams.CallbackDone(sqrt, localparams.ManualReset, localparams.CallID);

        }, new CalcParams()

        {                       

            //these are the values for the 2nd level thread

            ManualReset = m,

            CallID = i,

            CallbackDone = (r2, m2, i2) =>

            {

                //in the 3rd level callback im calculation the double of the result of 

                //the previous calculation

                int doublesqrt = r2 * 2;

                //im showing the result and the call id to the user

                AddTextAsync(string.Format(“The result for Callid {1} is {0}\n”, doublesqrt, i2));

                //set the top level ManualResetEvent

                m2.Set();

            }

        });

    }

});        

}

 

The same logic can be used to execute n levels of chains of threads by simply copying the last level thread inside the last callback you will be passing the ManualResetEvent to the deepest level to set the main thread when the calculation is done.

Im pretty sure there is much easier way to do it using RX or any other framework available for the .Net Framework 4.0, but this example is intended to demonstrate how to do it for Silverlight using the ThreadPool and Actions only.