Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass parameters to a thread in C#?

Consider the following code :

namespace MyThreads
{
    public class HisThread
    {
        public int Thread2(int start, int end, int[] arr)
        {
            int sum = 0;
            // foreach (int i in arr)
            for (int i = start; i <= end; i++)
            {
                sum += arr[i];
            }
            return sum;
        }

    }


    public class MyThread
    {
        public void Thread1()
        {
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine("Hello world " + i);
                Thread.Sleep(1);
            }
        }
    }


    public class Test
    {

        public static void Main()
        {
            int[] arr = new int[30];
            for (int i = 0; i < 30; i++ )
            {
                arr[i] = i;
            }

            Console.WriteLine("Before start thread");

            // thread 1 - without params
            MyThread thr = new MyThread();
            Thread tid1 = new Thread(new ThreadStart(thr.Thread1)); // this one is OK
            tid1.Start();

            // thread 2 - with params
            HisThread thr2 = new HisThread();
            Thread tid2 = new Thread(new ParameterizedThreadStart(thr2.Thread2));
        }
    }

}

The first thread compiles fine (with no arguments) but the second thread produces

Error 1 No overload for 'Thread2' matches delegate 

Any idea how to fix that ?

Thanks

like image 841
JAN Avatar asked Sep 06 '25 02:09

JAN


2 Answers

ParameterizedThreadStart delegate requires method which accepts single parameter of objecttype:

public delegate void ParameterizedThreadStart(object obj)

I.e. your method should be

public class HisThread
{
    public void Thread2(object obj)
    {
        // ...
    }
}

Also there is method Thread.Start which accepts parameter:

 // thread 2 - with params
 HisThread thr2 = new HisThread();
 Thread tid2 = new Thread(new ParameterizedThreadStart(thr2.Thread2));
 tid2.Start(parameter);

If you are using .NET 4.5 you can use tasks instead:

 Task<int>.Run(() => thr2.Thread2(start, end, array))
like image 161
Sergey Berezovskiy Avatar answered Sep 07 '25 19:09

Sergey Berezovskiy


The problem with that code is that ParameterizedThreadStart is a delegate type, which means it is tied to a specific method signature -- in particular, that signature is void method(object). Your method Thread2 does not match that signature, hence the compiler error.

So how to solve it? It depends really.

ParameterizedThreadStart has that signature because it's the most generic approach ever. The idea behind it is that you can pass an object of some custom type that contains all the state your function needs, like this:

class Params
{
    public int Start { get; set; }
    public int End { get; set; }
    public int[] Array { get; set; }
}

var p = new Params { 0, 0, new int[0] };
var t = new Thread(thr2.Thread2);
t.Start(p);

public int Thread2(object param)
{
    var p = (Params)param;
    // and now get your arguments as p.Start etc.
}

While this works, it's unwieldy and forces you to abandon the most natural signature for Thread2. But you can do better by interposing an anonymous function to do the unpacking of arguments:

int start = 0, end = 0;
var arr = new int[0];
var t = new Thread(() => thr2.Thread2(start, end, arr));

If you choose to do this you have to be mindful of the fact that due to the mechanism the compiler uses to pass the arguments to the thread method, changing their values after t is defined but before it is started will make Thread2 see the changed values.

like image 27
Jon Avatar answered Sep 07 '25 20:09

Jon