Preface
Thread is defined as the execution path of the program, and each thread performs specific work. When the C# program starts, the main thread is automatically created.
Thread life cycle
- Not started
- Ready status
- Not run state
- Death state
Create a Thread without parameters
void acceptThread(){ //TODO } Thread threadAccept = new Thread(new ThreadStart(acceptThread)); ();
Create a Thread with parameters
There are two ways to pass parameters to threads. One way is to use aParameterizedThreadStart
The Thread constructor for delegating parameters, another way isCreate a custom class
, define the method of the thread as an instance method, so that the data of the instance can be initialized and then the thread can be started.
Method 1: Use ParameterizedThreadStart Delegate
If usedParameterizedThreadStart
Delegate, the thread's entry must have an object-type parameter and the return type is void. Let’s look at the following example:
using System; using ; namespace ThreadWithParameters { class Program { static void Main(string[] args) { string hello = "hello world"; //This can also be abbreviated as Thread thread = new Thread(ThreadMainWithParameters); //But in order to let everyone know that the ParameterizedThreadStart commission is used here, there is no abbreviation Thread thread = new Thread(new ParameterizedThreadStart(ThreadMainWithParameters)); (hello); (); } static void ThreadMainWithParameters(object obj) { string str = obj as string; if(!(str)) ("Running in a thread,received: {0}", str); } } }
What's a little troublesome here is that the parameters in the ThreadMainWithParameters method must be of object type, and we need to perform type conversion. Why must the parameters be of object type? You can find out by looking at the declaration of ParameterizedThreadStart delegation.
public delegate void ParameterizedThreadStart(object obj); // Statement of ParameterizedThreadStart delegation
Method 2: Create a custom class
Define a class where the required fields are defined, and define the thread's main method as an instance method of the class.
using System; using ; namespace ThreadWithParameters { public class MyThread { private string data; public MyThread(string data) { = data; } public void ThreadMain() { ("Running in a thread,data: {0}", data); } } class Program { static void Main(string[] args) { MyThread myThread = new MyThread("hello world"); Thread thread = new Thread(); (); (); } } }
The disadvantage of this method is that when encountering a time-consuming method, create a new class.
So is there any better way to neither cast or create a new class?
Using anonymous methods
Method 3: Use anonymous method
using System; using ; namespace ThreadWithParameters { class Program { static void Main(string[] args) { string hello = "hello world"; //If you write Thread thread = new Thread(ThreadMainWithParameters(hello)); this form will report an error during compilation Thread thread = new Thread(() => ThreadMainWithParameters(hello)); (); (); } static void ThreadMainWithParameters(string str) { ("Running in a thread,received: {0}", str); } } }
This way, it runs successfully without type casting or new class.
But why does this method work? After decompiling it with ildasm, it was found that the third method listed above is actually the same as the second method, except that the custom class compiler helped us do it.
The following is the IL code decompiled by the third main method:
.method private hidebysig static void Main(string[] args) cil managed { .entrypoint // Code size 51 (0x33) .maxstack 3 .locals init ([0] class [mscorlib] thread, [1] class /'<>c__DisplayClass1' 'CS$<>8__locals2') IL_0000: newobj instance void /'<>c__DisplayClass1'::.ctor() IL_0005: stloc.1 IL_0006: nop IL_0007: ldloc.1 IL_0008: ldstr "hello world" IL_000d: stfld string /'<>c__DisplayClass1'::hello IL_0012: ldloc.1 IL_0013: ldftn instance void /'<>c__DisplayClass1'::'<Main>b__0'() IL_0019: newobj instance void [mscorlib]::.ctor(object, native int) IL_001e: newobj instance void [mscorlib]::.ctor(class [mscorlib]) IL_0023: stloc.0 IL_0024: ldloc.0 IL_0025: callvirt instance void [mscorlib]::Start() IL_002a: nop IL_002b: call int32 [mscorlib]::Read() IL_0030: pop IL_0031: nop IL_0032: ret } // end of method Program::Main
Let's look at the second way of IL code:
.method private hidebysig static void Main(string[] args) cil managed { .entrypoint // Code size 44 (0x2c) .maxstack 3 .locals init ([0] class myThread, [1] class [mscorlib] thread) IL_0000: nop IL_0001: ldstr "hello world" IL_0006: newobj instance void ::.ctor(string) IL_000b: stloc.0 IL_000c: ldloc.0 IL_000d: ldftn instance void ::ThreadMain() IL_0013: newobj instance void [mscorlib]::.ctor(object, native int) IL_0018: newobj instance void [mscorlib]::.ctor(class [mscorlib]) IL_001d: stloc.1 IL_001e: ldloc.1 IL_001f: callvirt instance void [mscorlib]::Start() IL_0024: nop IL_0025: call int32 [mscorlib]::Read() IL_002a: pop IL_002b: ret } // end of method Program::Main
Comparing the two-end code, we can find that both have a newobj. The purpose of this sentence is to initialize an instance of a class. The third method is to generate a class by the compiler: c__DisplayClass1
IL_0000: newobj instance void /'<>c__DisplayClass1'::.ctor() IL_0006: newobj instance void ::.ctor(string)
The above is the detailed content of several methods of C# passing parameters to multi-threaded parameters. For more information about C#'s multi-threaded parameters, please pay attention to my other related articles!