Example analysis of three ways of transferring parameters to multithread by C
- 2021-08-28 20:54:22
- OfStack
In this paper, three ways of C # to transmit parameters to multithreads are described by examples. Share it for your reference, as follows:
From "C # Advanced Programming", we know that there are two ways to pass parameters to threads, one is to use Thread constructor with ParameterizedThreadStart delegate parameters, and the other is to create a custom class and define the methods of threads as the methods of instances, so that the data of instances can be initialized, and then the threads can be started.
Mode 1: Use ParameterizedThreadStart delegate
If an ParameterizedThreadStart delegate is used, the entry of the thread must have a parameter of type object and a return type of void. Let's look at the following example:
using System;
using System.Threading;
namespace ThreadWithParameters
{
class Program
{
static void Main(string[] args)
{
string hello = "hello world";
// It can also be abbreviated here as Thread thread = new Thread(ThreadMainWithParameters);
// But in order to let everyone know that what is used here is ParameterizedThreadStart Commissioned, there is no abbreviation
Thread thread = new Thread(new ParameterizedThreadStart(ThreadMainWithParameters));
thread.Start(hello);
Console.Read();
}
static void ThreadMainWithParameters(object obj)
{
string str = obj as string;
if(!string.IsNullOrEmpty(str))
Console.WriteLine("Running in a thread,received: {0}", str);
}
}
}
A little bit of trouble here is that the parameters in the ThreadMainWithParameters method must be of type object, so we need to type conversion. Just look at the declaration of the ParameterizedThreadStart delegate to see why the parameter must be of type object.
public delegate void ParameterizedThreadStart (object obj); //ParameterizedThreadStart Declaration of Delegation
Way 2: Create a custom class
Define a class, in which the definition of the required fields, the main method of the thread is defined as a class of instance method, said is not very clear, or see the actual example.
using System;
using System.Threading;
namespace ThreadWithParameters
{
public class MyThread
{
private string data;
public MyThread(string data)
{
this.data = data;
}
public void ThreadMain()
{
Console.WriteLine("Running in a thread,data: {0}", data);
}
}
class Program
{
static void Main(string[] args)
{
MyThread myThread = new MyThread("hello world");
Thread thread = new Thread(myThread.ThreadMain);
thread.Start();
Console.Read();
}
}
}
I am not very satisfied with this method, so I can't create a new class if I encounter a time-consuming method. . .
So what better way is not to force type conversion or create a new class?
The following is an introduction to a method I found inadvertently. I don't remember where I saw it. Sin. .
Mode 3: Use anonymous methods
using System;
using System.Threading;
namespace ThreadWithParameters
{
class Program
{
static void Main(string[] args)
{
string hello = "hello world";
// If it is written as Thread thread = new Thread(ThreadMainWithParameters(hello)); In this form, an error will be reported at compile time
Thread thread = new Thread(() => ThreadMainWithParameters(hello));
thread.Start();
Console.Read();
}
static void ThreadMainWithParameters(string str)
{
Console.WriteLine("Running in a thread,received: {0}", str);
}
}
}
Wow, you will find that it runs successfully without casting or creating a new class.
But why can this method work? According to the prompt of @ Flurry Spring and Autumn yesterday, I also decompiled it with ildasm. Indeed, as he said, my so-called third method is actually the same as the second method, but the custom class compiler did it for us.
The following is the IL code decompiled by the main method in the third way:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 51 (0x33)
.maxstack 3
.locals init ([0] class [mscorlib]System.Threading.Thread thread,
[1] class ThreadWithParameters.Program/'<>c__DisplayClass1' 'CS$<>8__locals2')
IL_0000: newobj instance void ThreadWithParameters.Program/'<>c__DisplayClass1'::.ctor()
IL_0005: stloc.1
IL_0006: nop
IL_0007: ldloc.1
IL_0008: ldstr "hello world"
IL_000d: stfld string ThreadWithParameters.Program/'<>c__DisplayClass1'::hello
IL_0012: ldloc.1
IL_0013: ldftn instance void ThreadWithParameters.Program/'<>c__DisplayClass1'::'<Main>b__0'()
IL_0019: newobj instance void [mscorlib]System.Threading.ThreadStart::.ctor(object, native int)
IL_001e: newobj instance void [mscorlib]System.Threading.Thread::.ctor(class [mscorlib]System.Threading.ThreadStart)
IL_0023: stloc.0
IL_0024: ldloc.0
IL_0025: callvirt instance void [mscorlib]System.Threading.Thread::Start()
IL_002a: nop
IL_002b: call int32 [mscorlib]System.Console::Read()
IL_0030: pop
IL_0031: nop
IL_0032: ret
} // end of method Program::Main
Look at the IL code for Mode 2:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 44 (0x2c)
.maxstack 3
.locals init ([0] class ThreadWithParameters.MyThread myThread,
[1] class [mscorlib]System.Threading.Thread thread)
IL_0000: nop
IL_0001: ldstr "hello world"
IL_0006: newobj instance void ThreadWithParameters.MyThread::.ctor(string)
IL_000b: stloc.0
IL_000c: ldloc.0
IL_000d: ldftn instance void ThreadWithParameters.MyThread::ThreadMain()
IL_0013: newobj instance void [mscorlib]System.Threading.ThreadStart::.ctor(object, native int)
IL_0018: newobj instance void [mscorlib]System.Threading.Thread::.ctor(class [mscorlib]System.Threading.ThreadStart)
IL_001d: stloc.1
IL_001e: ldloc.1
IL_001f: callvirt instance void [mscorlib]System.Threading.Thread::Start()
IL_0024: nop
IL_0025: call int32 [mscorlib]System.Console::Read()
IL_002a: pop
IL_002b: ret
} // end of method Program::Main
Comparing the codes at both ends, we can find that both of them have an newobj, which is used to initialize an instance of a class. In the third way, the compiler generates a class: c__DisplayClass1
IL_0000: newobj instance void ThreadWithParameters.Program/'<>c__DisplayClass1'::.ctor()
IL_0006: newobj instance void ThreadWithParameters.MyThread::.ctor(string)
Note: Simplicity is not necessarily a good thing. Anonymous methods can easily cause imperceptible errors
I hope this article is helpful to everyone's C # programming.