首页 > 编程 > C# > 正文

C#实现向多线程传参的三种方式实例分析

2019-10-29 21:36:46
字体:
来源:转载
供稿:网友

这篇文章主要介绍了C#实现向多线程传参的三种方式,以实例形式较为详细的分析了C#多线程及参数传递的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下

本文实例讲述了C#实现向多线程传参的三种方式。分享给大家供大家参考,具体如下:

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

方式一:使用ParameterizedThreadStart委托

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

 

  1. using System; 
  2. using System.Threading; 
  3. namespace ThreadWithParameters 
  4. class Program 
  5. static void Main(string[] args) 
  6. string hello = "hello world"
  7. //这里也可简写成Thread thread = new Thread(ThreadMainWithParameters); 
  8. //但是为了让大家知道这里用的是ParameterizedThreadStart委托,就没有简写了 
  9. Thread thread = new Thread(new ParameterizedThreadStart(ThreadMainWithParameters)); 
  10. thread.Start(hello); 
  11. Console.Read(); 
  12. static void ThreadMainWithParameters(object obj) 
  13. string str = obj as string; 
  14. if(!string.IsNullOrEmpty(str)) 
  15. Console.WriteLine("Running in a thread,received: {0}", str); 

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

public delegate void ParameterizedThreadStart(object obj); //ParameterizedThreadStart委托的声明

方式二:创建自定义类

定义一个类,在其中定义需要的字段,将线程的主方法定义为类的一个实例方法,说得不是很明白,还是看实际的例子吧。

 

 
  1. using System; 
  2. using System.Threading; 
  3. namespace ThreadWithParameters 
  4. public class MyThread 
  5. private string data; 
  6. public MyThread(string data) 
  7. this.data = data; 
  8. public void ThreadMain() 
  9. Console.WriteLine("Running in a thread,data: {0}", data); 
  10. class Program 
  11. static void Main(string[] args) 
  12. MyThread myThread = new MyThread("hello world"); 
  13. Thread thread = new Thread(myThread.ThreadMain); 
  14. thread.Start(); 
  15. Console.Read(); 

对这种方法也不是很满意,总不能一遇到比较耗时的方法,就新建一个类吧。。。

那有什么更好办法即不用强制类型转换,也不用新建一个类呢?

下面就介绍下我无意中找到的一个方法,具体是在哪见过的我也不记得了,罪过啊。。

方式三:使用匿名方法

 

 
  1. using System; 
  2. using System.Threading; 
  3. namespace ThreadWithParameters 
  4. class Program 
  5. static void Main(string[] args) 
  6. string hello = "hello world"
  7. //如果写成Thread thread = new Thread(ThreadMainWithParameters(hello));这种形式,编译时就会报错 
  8. Thread thread = new Thread(() => ThreadMainWithParameters(hello)); 
  9. thread.Start(); 
  10. Console.Read(); 
  11. static void ThreadMainWithParameters(string str) 
  12. Console.WriteLine("Running in a thread,received: {0}", str); 

哇,你会发现既不用类型强制转换也不用新建类就运行成功了。

但是为什么这种方式能行呢,根据昨天 @乱舞春秋 的提示,我也用ildasm反编译了一下,确实如他所说,我所谓的第三种方式其实和第二种方式是一样的,只不过自定义类编译器帮我们做了。

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

 

 
  1. .method private hidebysig static void Main(string[] args) cil managed 
  2. .entrypoint 
  3. // 代码大小 51 (0x33) 
  4. .maxstack 3 
  5. .locals init ([0] class [mscorlib]System.Threading.Thread thread, 
  6. [1] class ThreadWithParameters.Program/'<>c__DisplayClass1' 'CS#FormatTableID_3#lt;>8__locals2'
  7. IL_0000: newobj instance void ThreadWithParameters.Program/'<>c__DisplayClass1'::.ctor() 
  8. IL_0005: stloc.1 
  9. IL_0006: nop 
  10. IL_0007: ldloc.1 
  11. IL_0008: ldstr "hello world" 
  12. IL_000d: stfld string ThreadWithParameters.Program/'<>c__DisplayClass1'::hello 
  13. IL_0012: ldloc.1 
  14. IL_0013: ldftn instance void ThreadWithParameters.Program/'<>c__DisplayClass1'::'<Main>b__0'() 
  15. IL_0019: newobj instance void [mscorlib]System.Threading.ThreadStart::.ctor(object, native int
  16. IL_001e: newobj instance void [mscorlib]System.Threading.Thread::.ctor(class [mscorlib]System.Threading.ThreadStart) 
  17. IL_0023: stloc.0 
  18. IL_0024: ldloc.0 
  19. IL_0025: callvirt instance void [mscorlib]System.Threading.Thread::Start() 
  20. IL_002a: nop 
  21. IL_002b: call int32 [mscorlib]System.Console::Read() 
  22. IL_0030: pop 
  23. IL_0031: nop 
  24. IL_0032: ret 
  25. // end of method Program::Main 

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

 

 
  1. .method private hidebysig static void Main(string[] args) cil managed 
  2. .entrypoint 
  3. // 代码大小 44 (0x2c) 
  4. .maxstack 3 
  5. .locals init ([0] class ThreadWithParameters.MyThread myThread, 
  6. [1] class [mscorlib]System.Threading.Thread thread) 
  7. IL_0000: nop 
  8. IL_0001: ldstr "hello world" 
  9. IL_0006: newobj instance void ThreadWithParameters.MyThread::.ctor(string) 
  10. IL_000b: stloc.0 
  11. IL_000c: ldloc.0 
  12. IL_000d: ldftn instance void ThreadWithParameters.MyThread::ThreadMain() 
  13. IL_0013: newobj instance void [mscorlib]System.Threading.ThreadStart::.ctor(object, native int
  14. IL_0018: newobj instance void [mscorlib]System.Threading.Thread::.ctor(class [mscorlib]System.Threading.ThreadStart) 
  15. IL_001d: stloc.1 
  16. IL_001e: ldloc.1 
  17. IL_001f: callvirt instance void [mscorlib]System.Threading.Thread::Start() 
  18. IL_0024: nop 
  19. IL_0025: call int32 [mscorlib]System.Console::Read() 
  20. IL_002a: pop 
  21. IL_002b: ret 
  22. // end of method Program::Main 

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

 

 
  1. IL_0000: newobj instance void ThreadWithParameters.Program/'<>c__DisplayClass1'::.ctor() 
  2. IL_0006: newobj instance void ThreadWithParameters.MyThread::.ctor(string) 

注意:简单并不一定是好事,匿名方法容易造成不易察觉的错误

希望本文所述对大家C#程序设计有所帮助。


注:相关教程知识阅读请移步到c#教程频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表