向线程传递数据
- 如果你想往线程的启动方法里传递参数,最简单的方式就是使用lambda表达式,在里面使用参数调用方法。 ```csharp using System; using System.Threading;
namespace ThreadTest { class Program { static void Main() { new Thread(() => Print(“Hello World!”)).Start(); }
static void Print(string message)
{
Console.WriteLine(message);
}
}
}
- 甚至可以把整个逻辑都放在lambda里面。
```csharp
using System;
using System.Threading;
namespace ThreadTest
{
class Program
{
static void Main()
{
new Thread(() =>
{
Console.WriteLine("Hello World!");
Console.WriteLine("Hi~");
}).Start();
}
}
}
向线程传递数据在C#3.0之前
- 在C#3.0之前,没有lambda表达式。可以使用Thread的Start方法来传递参数。 ```csharp using System; using System.Threading;
namespace ThreadTest { class Program { static void Main() { new Thread(Print).Start(“Hello World!”); }
static void Print(object message) // object类型
{
Console.WriteLine(message.ToString());
}
}
}
- Thread的重载构造函数可以接受下列两个委托之一作为参数:
- `public delegate void ThreadStart();`
- `public dalegate void ParameterizedThreadStart(object obj)`
<a name="2ea23"></a>
## Lambda表达式与被捕获的变量
- 使用Lambda表达式可以很简单的给Thread传递参数。但是线程开始后,可能会不小心修改了被捕获的变量,这要多加注意。
```csharp
using System;
using System.Threading;
namespace ThreadTest
{
class Program
{
static void Main()
{
for (int i = 0; i < 10; i++)
{
new Thread(() => Console.Write(i)).Start();
}
}
// i 在循环的整个生命周期内指向的是同一个内存地址
// 每个线程对Console.WriteLine()的调用都会在它运行的时候进行修改。
}
}
- 解决方案(但是顺序还是无法保证) ```csharp using System; using System.Threading;
namespace ThreadTest { class Program { static void Main() { for (int i = 0; i < 10; i++) { int temp = i; new Thread(() => Console.Write(temp)).Start(); } }
// 顺序仍然无法保证
}
}
<a name="9f65u"></a>
## 异常处理
- 创建线程时在作用范围内的try/catch/finally块,在线程开始执行后就与线程无关了。
```csharp
using System;
using System.Threading;
namespace ThreadTest
{
class Program
{
static void Main()
{
try
{
new Thread(Go).Start();
}
catch (Exception e)
{
// 从不执行到这
Console.WriteLine("Exception!" + e.Message);
}
}
static void Go()
{
throw new NullReferenceException();
}
// 补救方法就是把异常处理放在Go方法里面
}
}
-------------------------------------------处理------------------
using System;
using System.Threading;
namespace ThreadTest
{
class Program
{
static void Main()
{
new Thread(Go).Start();
}
static void Go()
{
try
{
throw new NullReferenceException();
}
catch (Exception e)
{
Console.WriteLine("Exception!" + e.Message);
}
}
}
}
- 在WPF、WinForm里,可以订阅全局异常处理事件:
- Application.DispatcherUnhandleException
- Application.ThreadException
- 触发:在通过消息循环调用的程序的任何部分发生未处理的异常(这相当于应用程序处于活动状态时,在主线程上运行的所有代码)后,将触发这些异常。
- 但是非UI线程上的未处理异常,并不会触发它。
- 而任何线程有任何未处理的异常都会触发
- AppDomain.CurrentDomain.UnhandleException