• c#给多线程传参的几种方式


    前言

    线程 被定义为程序的执行路径,每个线程执行特定的工作。当C#程序开始时,主线程自动创建。

    线程生命周期
    • 未启动状态
    • 就绪状态
    • 不可运行状态
    • 死亡状态
    创建无参Thread
    void acceptThread(){
    //TODO
    }
    Thread threadAccept = new Thread(new ThreadStart(acceptThread));
    threadAccept.start();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    创建有参Thread

    给线程传递参数有两种方式,一种方式是使用带ParameterizedThreadStart委托参数的Thread构造函数,另一种方式是创建一个自定义类,把线程的方法定义为实例的方法,这样就可以初始化实例的数据,之后启动线程。

    方式一:使用ParameterizedThreadStart委托

    如果使用了ParameterizedThreadStart委托,线程的入口必须有一个object类型的参数,且返回类型为void。且看下面的例子:

    using System;
    using System.Threading;
    
    namespace ThreadWithParameters
    {
        class Program
        {
            static void Main(string[] args)
            {
                string hello = "hello world";
                //这里也可简写成Thread thread = new Thread(ThreadMainWithParameters);
                //但是为了让大家知道这里用的是ParameterizedThreadStart委托,就没有简写了
                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);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    这里稍微有点麻烦的就是ThreadMainWithParameters方法里的参数必须是object类型的,我们需要进行类型转换。为什么参数必须是object类型呢,各位看看ParameterizedThreadStart委托的声明就知道了。

    public delegate void ParameterizedThreadStart(object obj);   //ParameterizedThreadStart委托的声明
    
    • 1
    方式二:创建自定义类

    定义一个类,在其中定义需要的字段,将线程的主方法定义为类的一个实例方法

    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();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    这种方法的缺点在于遇到一个耗时的方法,就新建一个类。
    那有什么更好办法既不用强制类型转换,也不用新建一个类呢?
    使用匿名方法

    方式三:使用匿名方法
    using System;
    using System.Threading;
    
    namespace ThreadWithParameters
    {
        class Program
        {
            static void Main(string[] args)
            {
                string hello = "hello world";
    
                //如果写成Thread thread = new Thread(ThreadMainWithParameters(hello));这种形式,编译时就会报错
                Thread thread = new Thread(() => ThreadMainWithParameters(hello));
                thread.Start();
                Console.Read();
            }
    
            static void ThreadMainWithParameters(string str)
            {
                 Console.WriteLine("Running in a thread,received: {0}", str);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    这样既不用类型强制转换也不用新建类就运行成功了。

    但是为什么这种方式能行呢,用ildasm反编译后发现,上述说列出来的第三种方式其实和第二种方式是一样的,只不过自定义类编译器帮我们做了。

    下面的是第三种方式main方法反编译的IL代码:

    .method private hidebysig static void  Main(string[] args) cil managed
      {
        .entrypoint
        // 代码大小       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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    在看看第二种方式的IL代码:

     .method private hidebysig static void  Main(string[] args) cil managed
      {
        .entrypoint
        // 代码大小       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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    比较两端代码,可以发现两者都有一个newobj,这句的作用是初始化一个类的实例,第三种方式由编译器生成了一个类:c__DisplayClass1

    IL_0000:  newobj     instance void ThreadWithParameters.Program/'<>c__DisplayClass1'::.ctor()
    IL_0006:  newobj     instance void ThreadWithParameters.MyThread::.ctor(string)
    
    • 1
    • 2
    参考文献
    • https://blog.csdn.net/weixin_45967200/article/details/106886042
    • https://www.cnblogs.com/lexiaoyao/archive/2011/12/01/2271120.html
  • 相关阅读:
    谈谈大学两年的学习经历
    【BLE】蓝牙Profile
    gitLab更新11.11.3->16.1.5
    jetsonTX2 nx配置yolov5和D435I相机,完整步骤
    docker for windonws--Windows 10 家庭中文版安装clickhouse 22.3版本及配置
    ”互联网行业还在等金三银四或是金九银十?“,我劝你还是早做打算
    面向高速公路车辆切入场景的自动驾驶测试用例生成方法
    31-k8s集群svc的代理模式-iptables修改为ipvs
    Windows通过ssh免密登录Ubuntu (3)
    大模型的数据调度
  • 原文地址:https://blog.csdn.net/weixin_35770067/article/details/126394114