views:

496

answers:

4

How to pass more than one parameter to a C# thread? Any example will be appreciated.

A: 

Send multiple parameters to a thread in C#. We have a similar question as well C# thread with multiple parameters

Shoban
+3  A: 

Suppose you have a method:

void A(string a, int b) {}

This should work:

ThreadStart starter = delegate { A("word", 10); };
Thread thread = new Thread(starter);

thread.Start();
tsocks
`new Thread(() => A("word", 10))` for C#3+.
Dykam
Exactly.I was thinking of .NET 2.0.
tsocks
@Dykam, can you elaborate the meaning of "()=>" in the example given by you( new Thread(() => A("word", 10)) )
Techee
Yes. with C#2, you create a delegate taking no arguments, by using `delegate {/*statements here*/}`, with C#3, you can create a so called lambda, with a single argument, with the following: `x => { /*statements here */ }`, which is a anonymous method taking one argument. To make it accept no argument or more than one, you use parentheses to specify this: `() => {/*statements*/}` and `(arg1, agr2) => {/*statements*/}`. In case you only have one statement or expression, you can leave out the outer brackets, as in this case.
Dykam
@Dykam: `new Thread(() => A("word", 10)).Start();`
modosansreves
Only in case you don´t need a reference to the thread.
Dykam
A: 

The solutions tsocks has given might not be good for all situations (although in a lot of cases it is perfectly good) because it specifies the parameters at the time of the creation of the ThreadStart delegate, instead of at the time of execution. This could lead to errors because the parameters might change before the execution which is probably not what you want. Suppose you need to create several threads in a loop, each with it's own parameters:

void CreateAndRunThreads()
{
    List<ThreadStart> threadStartsList = new List<ThreadStart>();

    //delegate creation
    for (int i = 0; i < 5; i++)
    {
        ThreadStart ts = delegate() { PrintInteger(i); };
        threadStartsList.Add(ts);
    }

    //delegate execution (at this moment i=5 in the previous loop)
    foreach(ThreadStart ts in threadStartsList)
    {
        Thread t = new Thread(ts);
        t.Start();
    }
}
private void PrintInteger(int i)
{
    Debug.WriteLine("The integer value: "+i);
}

The output here is as follows:

The integer value: 5
The thread 0x17f0 has exited with code 0 (0x0).
The integer value: 5
The integer value: 5
The thread 0x10f4 has exited with code 0 (0x0).
The integer value: 5
The thread 0x1488 has exited with code 0 (0x0).
The integer value: 5
The thread 0x684 has exited with code 0 (0x0).

Notice that all delegates printed the value 5, not 0 through 4. This is because the ThreadStart delegates use the variable "i", as it is at the moment of execution, not at the moment of the creation of the delegate. So any change (i++ in the loop) to the parameter after the moment of the creation of the delegate will be reflected in the value of the parameter as the delegate executes.

A solution to this problem is to use ParameterizedThreadStart and a custom class which aggregates all your parameters(if there are more). With parameterizedThreadStart, you pass the parameters at the time of execution. This would look something like this:

    class CustomParameters
{
    public int IntValue { get; set; }
    public string FriendlyMessage { get; set; }
}

private void CreateAndRunThreadsWithParams()
{
    List<ParameterizedThreadStart> threadStartsList = new List<ParameterizedThreadStart>();

    //delegate creation
    for (int i = 0; i < 5; i++)
    {
        ParameterizedThreadStart ts = delegate(object o) { PrintCustomParams((CustomParameters)o); };
        threadStartsList.Add(ts);
    }

    //delegate execution
    for (int i=0;i<threadStartsList.Count;i++)
    {
        Thread t = new Thread(threadStartsList[i]);
        t.Start(new CustomParameters() { IntValue = i, FriendlyMessage = "Hello friend! Your integer value is:{0}"});
    }
}

private void PrintCustomParams(CustomParameters customParameters)
{
    Debug.WriteLine(string.Format(customParameters.FriendlyMessage, customParameters.IntValue));
}

The output is shown here:

    Hello friend! Your integer value is:1
The thread 0x1510 has exited with code 0 (0x0).
Hello friend! Your integer value is:0
The thread 0x13f4 has exited with code 0 (0x0).
Hello friend! Your integer value is:2
The thread 0x157c has exited with code 0 (0x0).
Hello friend! Your integer value is:3
The thread 0x14e4 has exited with code 0 (0x0).
Hello friend! Your integer value is:4
The thread 0x1738 has exited with code 0 (0x0).

(The order of execution is not deterministic, it's a race between the threads)

Sorry for the long answer, hope somebody finds it useful.

Antonio Nakic Alfirevic
A: 

For C# 3.0 you can avoid the ugly object array passing with anonymous methods:

void Run()
{
    string param1 = "hello";
    int param2 = 42;

    Thread thread = new Thread(delegate()
    {
        MyMethod(param1,param2);
    });
    thread.Start();
}

void MyMethod(string p,int i)
{

}
Chris S