1.多线程数据的输出
lambda 表达式是向线程传递数据的最强大的方法。然而必须小心,不要在启动线程之后误修改被捕获变量(captured variables)。例如,考虑下面的例子:
for (int i = 0; i < 10; i++)
new Thread (() => Console.Write (i)).Start();
输出结果是不确定的!可能是这样0223557799
。
问题在于变量i
在整个循环中指向相同的内存地址。所以,每一个线程在调用Console.Write
时,都在使用这个值在运行时会被改变的变量!
类似的问题在C# 4.0 in a Nutshell的第 8 章的 “Captured Variables” 有描述。这个问题与多线程没什么关系,而是和 C# 的捕获变量的规则有关(在for
和foreach
的场景下有时不是很理想)。
解决方法就是使用临时变量,如下所示:
for (int i = 0; i < 10; i++)
{
int temp = i;
new Thread (() => Console.Write (temp)).Start();
}
2.多线程委托的实现方,变量就不用使用object进行中间转换了
class Program
{
static void Main(string[] args)
{
Thread t = new Thread(delegate ()
{
Print(1);
});
t.Start();
Console.ReadKey();
}
private static void Print(int v)
{
Console.WriteLine(v);
}
}
3.多线程的异常处理以及捕获
下面这种方法是永远不会捕获到异常的,每一个线程具有独立的执行路径及其独立的资源空间,所以不会执行
public static void Main()
{
try { new Thread (Go).Start();
}
catch (Exception ex)
{
// 永远执行不到这里 Console.WriteLine ("Exception!");
}
}
static void Go() { throw null; } // 产生 NullReferenceException 异常
解决方法就是把捕获异常的语句放到子方法中
public static void Main()
{
new Thread (Go).Start();
}
static void Go()
{
try { // ... throw null; // 异常会在下面被捕获 // ...
}
catch (Exception ex)
{
// 一般会记录异常, 和/或通知其它线程我们遇到问题了 // ...
}
}