322

How do you start a thread with parameters in C#?

2-bits
  • 453
  • 6
  • 12
JL.
  • 78,954
  • 126
  • 311
  • 459
  • The answer to this question varies widely across versions of the runtime - is a 3.5 answer fine? – quillbreaker Jul 28 '09 at 18:39
  • 6
    Wow. I've been editing some of your old questions, but it could be a full-time job. I had forgotten, uh, how much you've improved over the years. :-) – John Saunders Dec 26 '13 at 19:56
  • 3
    If I asked such a brief question I would get 5 negative scores or even more! Although the question and answer helped me. – Muhammad Musavi Dec 24 '19 at 06:28
  • This answer still helpful after 12 years, @MuhammadMusavi this question was asked 9 years ago (2019) so no wonder you would get negative if this were to be asked now considering there are a lot of articles for this question and materials – Aimkiller Apr 22 '22 at 06:19

15 Answers15

569

One of the 2 overloads of the Thread constructor takse a ParameterizedThreadStart delegate which allows you to pass a single parameter to the start method. Unfortunately though it only allows for a single parameter and it does so in an unsafe way because it passes it as object. I find it's much easier to use a lambda expression to capture the relevant parameters and pass them in a strongly typed fashion.

Try the following

public Thread StartTheThread(SomeType param1, SomeOtherType param2) {
  var t = new Thread(() => RealStart(param1, param2));
  t.Start();
  return t;
}

private static void RealStart(SomeType param1, SomeOtherType param2) {
  ...
}
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • 47
    +1: Even though the currently selected answer is absolutely correct, this one by JaredPar is the better one. It simply is the best solution for most practical cases. – galaktor Oct 10 '09 at 10:27
  • 3
    This solution is much better then the standrard ParameterizedThreadStart – Piotr Owsiak Jul 30 '10 at 13:33
  • 5
    Nice so simple. Just wrap any call in "new Thread(() => FooBar() ).Start(); – Thomas Jespersen Nov 29 '10 at 15:02
  • 13
    Awesome, this is for VB.NET guys `Dim thr As New Thread(Sub() DoStuff(settings))` – dr. evil Sep 17 '11 at 22:55
  • @ThomasJespersen in your example `new Thread(FooBar).Start();` works just as well, sparing a closure. – Clément Mar 24 '13 at 09:53
  • @JaredPar, `public Task(Delegate method) { Method = method; Thread = new Thread(() => method); }` does not work. How can I make it work so I can have a generic (not Generic) solution? – toddmo Dec 06 '13 at 18:02
  • @JaredPar in what sense is `ParameterizedThreadStart` unsafe? Do you mean static type checking, or is it something else? – bavaza Jan 09 '14 at 09:49
  • 3
    @bavaza I was just referring to the static type checking – JaredPar Jan 09 '14 at 13:53
  • Can someone translate this to VB? I'm stuck with it, and can't figure out how to write the lamba. – David Krider Aug 08 '14 at 14:37
  • 1
    Beware: If the parameter values change before the thread is actually started, the values passed will also be changed. See the comments on the accepted answer here: http://stackoverflow.com/questions/3360555/how-to-pass-parameters-to-threadstart-method-in-thread – Kaganar Apr 08 '15 at 18:21
195

Yep :

Thread t = new Thread (new ParameterizedThreadStart(myMethod));
t.Start (myParameterObject);
Nikhil Agrawal
  • 47,018
  • 22
  • 121
  • 208
Erick
  • 5,969
  • 10
  • 42
  • 61
177

You can use lambda expressions

private void MyMethod(string param1,int param2)
{
  //do stuff
}
Thread myNewThread = new Thread(() => MyMethod("param1",5));
myNewThread.Start();

this is so far the best answer i could find, it's fast and easy.

Georgi-it
  • 3,676
  • 1
  • 20
  • 23
  • 6
    Best solution for simple cases IMO – Dunc Apr 12 '13 at 13:12
  • 1
    what is that =>? and where can i find more information about the syntax? – Nick Aug 13 '13 at 08:56
  • 2
    This is a lambda expression, some info can be found on these addresses: msdn.microsoft.com/en-us/library/vstudio/bb397687.aspx | http://www.codeproject.com/Articles/24255/Exploring-Lambda-Expression-in-C | http://www.dotnetperls.com/lambda – Georgi-it Aug 13 '13 at 12:31
  • 1
    This worked for me. I tried the ParameterizedThreadStart and variations of it but had no joy. I was using .NET Framework 4 in a supposedly simple console application. – Daniel Hollinrake Mar 17 '14 at 12:18
  • 1
    This works best for people who are used to these kind of delegates. Might be difficult for beginners to udnerstand. This is clean for C# standards though. The accepted answer doesn't work for me and I don't have the time to find out why. – Bitterblue Jun 19 '18 at 08:32
  • the best solution – Igor Cova May 15 '20 at 13:43
  • How is this answer different from [JaredPar's answer](https://stackoverflow.com/a/1195915/7740405) ? – Maskim Oct 08 '20 at 06:41
40

Simple way using lambda like so..

Thread t = new Thread(() => DoSomething("param1", "param2"));
t.Start();

OR you could even delegate using ThreadStart like so...

private void DoSomething(int param1, string param2)
{
    //DO SOMETHING...
    ThreadStart ts = delegate
    {
        if (param1 > 0) DoSomethingElse(param2, "param3");
    };   
    new Thread(ts).Start();
    //DO SOMETHING...
}

OR using .NET 4.5+ even cleaner like so..

private void DoSomething(int param1, string param2)
{
    //DO SOMETHING..
    void ts()
    {
        if (param1 > 0) DoSomethingElse(param2, "param3");
    }
    new Thread(ts).Start();
    //DO SOMETHING..
}
Magic Mick
  • 1,475
  • 1
  • 21
  • 32
38
Thread thread = new Thread(Work);
thread.Start(Parameter);

private void Work(object param)
{
    string Parameter = (string)param;
}

The parameter type must be an object.

EDIT:

While this answer isn't incorrect I do recommend against this approach. Using a lambda expression is much easier to read and doesn't require type casting. See here: https://stackoverflow.com/a/1195915/52551

Community
  • 1
  • 1
Spencer Ruport
  • 34,865
  • 12
  • 85
  • 147
34
class Program
{
    static void Main(string[] args)
    {
        Thread t = new Thread(new ParameterizedThreadStart(ThreadMethod));

        t.Start("My Parameter");
    }

    static void ThreadMethod(object parameter)
    {
        // parameter equals to "My Parameter"
    }
}
huseyint
  • 14,953
  • 15
  • 56
  • 78
9

As has already been mention in various answers here, the Thread class currently (4.7.2) provides several constructors and a Start method with overloads.

These relevant constructors for this question are:

public Thread(ThreadStart start);

and

public Thread(ParameterizedThreadStart start);

which either take a ThreadStart delegate or a ParameterizedThreadStart delegate.

The corresponding delegates look like this:

public delegate void ThreadStart();
public delegate void ParameterizedThreadStart(object obj);

So as can be seen, the correct constructor to use seems to be the one taking a ParameterizedThreadStart delegate so that some method conform to the specified signature of the delegate can be started by the thread.

A simple example for instanciating the Thread class would be

Thread thread = new Thread(new ParameterizedThreadStart(Work));

or just

Thread thread = new Thread(Work);

The signature of the corresponding method (called Work in this example) looks like this:

private void Work(object data)
{
   ...
}

What is left is to start the thread. This is done by using either

public void Start();

or

public void Start(object parameter);

While Start() would start the thread and pass null as data to the method, Start(...) can be used to pass anything into the Work method of the thread.

There is however one big problem with this approach: Everything passed into the Work method is cast into an object. That means within the Work method it has to be cast to the original type again like in the following example:

public static void Main(string[] args)
{
    Thread thread = new Thread(Work);

    thread.Start("I've got some text");
    Console.ReadLine();
}

private static void Work(object data)
{
    string message = (string)data; // Wow, this is ugly

    Console.WriteLine($"I, the thread write: {message}");
}



Casting is something you typically do not want to do.

What if someone passes something else which is not a string? As this seems not possible at first (because It is my method, I know what I do or The method is private, how should someone ever be able to pass anything to it?) you may possibly end up with exactly that case for various reasons. As some cases may not be a problem, others are. In such cases you will probably end up with an InvalidCastException which you probably will not notice because it simply terminates the thread.

As a solution you would expect to get a generic ParameterizedThreadStart delegate like ParameterizedThreadStart<T> where T would be the type of data you want to pass into the Work method. Unfortunately something like this does not exist (yet?).

There is however a suggested solution to this issue. It involves creating a class which contains both, the data to be passed to the thread as well as the method that represents the worker method like this:

public class ThreadWithState
{
    private string message;

    public ThreadWithState(string message)
    {
        this.message = message;
    }

    public void Work()
    {
        Console.WriteLine($"I, the thread write: {this.message}");
    }
}

With this approach you would start the thread like this:

ThreadWithState tws = new ThreadWithState("I've got some text");
Thread thread = new Thread(tws.Work);

thread.Start();

So in this way you simply avoid casting around and have a typesafe way of providing data to a thread ;-)

Markus Safar
  • 6,324
  • 5
  • 28
  • 44
  • Wow, a downvote without comment... Either my answer is as bad as the cast or the reader did not understood what I tried to point out here ;-) – Markus Safar Dec 11 '18 at 22:19
  • 1
    I found your solution very enlightnen, congratulations. Just wanted to add that I have already tested in Net.Core the following and worked without having to explicity cast! :-) `private static void MyMethod(T myData) { T message = myData; Console.WriteLine($"the thread wrote: {message}"); }` – Paul Efford Jan 15 '20 at 19:04
  • @PaulEfford Thanks ;-) Your solution seems pretty nice. But you don't get access to type specific information as it will still be boxed to an object, right? (e.g. `message.Length` is not possible and so on) – Markus Safar Jan 16 '20 at 14:13
  • 1
    right... you could message.GetType() and cast if requiered any specific property like `if(myData.GetType() == typeof(string)) { var str = ((string)(object)myData).Length; }`. Anyway, instead of using your threading method I found a bit more comfortable to use `Tasks`, like for example `tasks.Add(Task.Run(() => Calculate(par1, par2, par3)))`, see my answer below (https://stackoverflow.com/a/59777250/7586301) – Paul Efford Jan 16 '20 at 20:22
5

I was having issue in the passed parameter. I passed integer from a for loop to the function and displayed it , but it always gave out different results. like (1,2,2,3) (1,2,3,3) (1,1,2,3) etc with ParametrizedThreadStart delegate.

this simple code worked as a charm

Thread thread = new Thread(Work);
thread.Start(Parameter);

private void Work(object param) 
{
 string Parameter = (string)param; 
}
user3805007
  • 61
  • 1
  • 1
4

The ParameterizedThreadStart takes one parameter. You can use that to send one parameter, or a custom class containing several properties.

Another method is to put the method that you want to start as an instance member in a class along with properties for the parameters that you want to set. Create an instance of the class, set the properties and start the thread specifying the instance and the method, and the method can access the properties.

Guffa
  • 687,336
  • 108
  • 737
  • 1,005
3

You could use a ParametrizedThreadStart delegate:

string parameter = "Hello world!";
Thread t = new Thread(new ParameterizedThreadStart(MyMethod));
t.Start(parameter);
Christian C. Salvadó
  • 807,428
  • 183
  • 922
  • 838
3

You can use the BackgroundWorker RunWorkerAsync method and pass in your value.

SwDevMan81
  • 48,814
  • 22
  • 151
  • 184
1
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace ConsoleApp6
{
    class Program
    {
        static void Main(string[] args)
        {

            int x = 10;
            Thread t1 =new Thread(new ParameterizedThreadStart(order1));
            t1.IsBackground = true;//i can stope 
            t1.Start(x);

            Thread t2=new Thread(order2);
            t2.Priority = ThreadPriority.Highest;
            t2.Start();

            Console.ReadKey();
        }//Main

        static void  order1(object args)
        {
            int x = (int)args;


                for (int i = 0; i < x; i++)
            {
                Console.ForegroundColor = ConsoleColor.Green;
                Console.Write(i.ToString() + " ");
            }
        }

        static void order2()
        {
            for (int i = 100; i > 0; i--)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.Write(i.ToString() + " ");
            }
        }`enter code here`
    }
}
0

I propose using Task<T>instead of Thread; it allows multiple parameters and executes really fine.

Here is a working example:

    public static void Main()
    {
        List<Task> tasks = new List<Task>();

        Console.WriteLine("Awaiting threads to finished...");

        string par1 = "foo";
        string par2 = "boo";
        int par3 = 3;

        for (int i = 0; i < 1000; i++)
        {
            tasks.Add(Task.Run(() => Calculate(par1, par2, par3))); 
        }

        Task.WaitAll(tasks.ToArray());

        Console.WriteLine("All threads finished!");
    }

    static bool Calculate1(string par1, string par2, int par3)
    {
        lock(_locker)
        {
            //...
            return true;
        }
    }

    // if need to lock, use this:
    private static Object _locker = new Object();"

    static bool Calculate2(string par1, string par2, int par3)
    {
        lock(_locker)
        {
            //...
            return true;
        }
    }
Paul Efford
  • 261
  • 4
  • 12
0

A very simple and convenient way using lambda expression can be like this:

Thread thread = new Thread( (param) => {
    string name = param as string;
    // rest of code goes here.
});
thread.Start("MyName");

This way a lambda expression can have parameters and run inline code in a separate thread.

-2
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace ConsoleApp6
{
    class Program
    {
        static void Main(string[] args)
        {

            int x = 10;
            Thread t1 =new Thread(new ParameterizedThreadStart(order1));
            t1.Start(x);

            Thread t2=new Thread(order2);
            t2.Priority = ThreadPriority.Highest;
            t2.Start();

            Console.ReadKey();
        }//Main

        static void  order1(object args)
        {
            int x = (int)args;


            for (int i = 0; i < x; i++)
            {
                Console.ForegroundColor = ConsoleColor.Green;
                Console.Write(i.ToString() + " ");
            }
        }

        static void order2()
        {
            for (int i = 100; i > 0; i--)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.Write(i.ToString() + " ");
            }
        }
    }
}