首页 > 代码库 > C# 的线程

C# 的线程

第1部分:起步

介绍和概念

c#支持通过多线程并行执行代码。线程是一个独立的执行路径,能够与其他线程同时运行。

 

一个c#客户端程序(控制台、WPF或Windows窗体)从一个由CLR和操作系统(“主”线程)自动创建的线程开始,并且通过创建额外的线程来实现多线程。下面是一个简单的示例及其输出:

 

所有的示例都假设导入了以下名称空间:

 

使用系统;

使用System.Threading;

类ThreadTest

{

静态void Main()

{

线程t = new Thread(WriteY);/ /启动一个新线程

t.Start();/ /运行WriteY()

 

/ /同时,在主线程上做一些事情。

for(int i = 0;i < 1000;i + +)控制台。写(“x”);

}

 

静态孔隙WriteY()

{

for(int i = 0;i < 1000;i + +)控制台。写(“y”);

}

}

xxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyy

yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxx

xxxxxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy

yyyyyyyyyyyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

……

主线程创建一个新的线程t,它运行一个重复打印字符“y”的方法。同时,主线程反复打印字符“x”:

 

开始一个新的线程

一旦启动,线程的IsAlive属性将返回true,直到线程结束。当传递到线程的构造函数的委托完成执行时,线程结束。一旦结束,线程无法重新启动。

 

CLR将每个线程分配其自己的内存堆栈,这样本地变量就会保持分离。在下一个示例中,我们定义了一个带有局部变量的方法,然后在主线程和新创建的线程上同时调用方法:

 

静态void Main()

{

新线程(Go). start();/ /调用Go()在新线程上

Go();/ / Call Go()在主线程上

}

 

静态空去()

{

/ /声明并使用局部变量—“循环”

for(int cycle = 0;循环< 5;循环+ +)控制台。写(‘ ? ‘);

}

? ? ? ? ? ? ? ? ? ?

每个线程的内存堆栈上都创建了一个单独的循环变量副本,因此可以预见,输出是10个问号。

 

如果线程共享同一个对象实例的公共引用,则共享数据。例如:

 

类ThreadTest

{

bool完成;

 

静态void Main()

{

ThreadTest tt = new ThreadTest();/ /创建一个通用实例

新线程(tt.Go).Start();

tt.Go();

}

 

/ /注意,Go现在是一个实例方法

空去()

{

如果(完成){ done = true;控制台。WriteLine(“完成”);}

}

}

因为两个线程都在同一个ThreadTest实例上调用Go(),它们共享完成的字段。这样做的结果是“完成”,而不是两次。

 

完成

静态字段提供了在线程之间共享数据的另一种方法。这里有一个与静态字段相同的例子:

 

类ThreadTest

{

静态的bool完成;/ /静态字段在所有线程之间共享

 

静态void Main()

{

新线程(去).Start();

();

}

 

静态空去()

{

如果(完成){ done = true;控制台。WriteLine(“完成”);}

}

}

这两个例子都说明了另一个关键概念:线程安全(或者更确切地说,是线程安全)。输出实际上是不确定的:有可能(尽管不太可能)“完成”可以打印两次。但是,如果我们在Go方法中交换语句的顺序,“完成”的概率就会急剧增加:

 

静态空去()

{

如果(!){控制台。WriteLine(“Done”);Done = true;

}

完成

完成(通常是!)

问题是,一个线程可以对if语句进行评估,而另一个线程正在执行WriteLine语句——在它有机会设置为true之前。

 

补救办法是在阅读和写作时获得一个独占锁。c#为这个目的提供了锁语句:

 

类为

{

静态弯曲件;

静态readonly对象locker = new object();

 

静态void Main()

{

新线程(去).Start();

();

}

 

静态空去()

{

锁(锁)

{

如果(!){控制台。WriteLine(“Done”);Done = true;

}

}

}

当两个线程同时争用一个锁(在本例中是一个锁),一个线程等待,或者阻塞,直到锁可用。在这种情况下,它只确保一个线程可以一次输入关键的代码段,并且“完成”将只打印一次。以这种方式保护的代码—从多线程上下文中的不确定性—称为线程安全。

 

共享数据是多线程中复杂性和模糊错误的主要原因。虽然通常是必要的,但要尽可能的简单。

 

线程虽然被阻塞,但不会消耗CPU资源。

 

加入和睡眠

您可以通过调用它的联接方法等待另一个线程结束。例如:

 

静态void Main()

{

线程t =新线程

C# 的线程