不可不知的C#基础 3. 线程浅析

线程可以使你的项目运行得更加的流畅.

什么是线程呢?

线程(thread)是程序执行流的最小单元, 是程序中一个单一的顺序控制流程. 每个程序最少有一个线程, 那就是程序本身.

在C#中, 你可以使用 System.Threading 提供的类,接口和方法实现线程的所有操作.

单线程操作

想象着你走进快餐店, 大叫一声"来碗兰州拉面", 然后就坐在饭桌上等. 当厨师听到你的要求时,他就开始做兰州拉面了. 理论上讲, 当你叫了以后, 厨师就已经收到了命令.

用代码可以这样表达:

 

static void Main(string[] args)
{
string name = "兰州拉面";
Console.WriteLine("来碗" + name);
PlaceOrder(name);
Console.WriteLine("坐在饭桌上....");
Console.Read();
}
static void PlaceOrder(string name)
{
Console.WriteLine("开始制作" + name);
}
 
运行程序, 你会发现输出结果是:

ScreenShot056

从显示的结果来看, 这个厨师的动作非常的快, 他一听到命令, 马上就开始了. 为了让这个程序的模拟比较真实, 我们可以想象"我的动作"是一个线程, 而"厨师做拉面"是一个线程.
如果我们运用线程来实现就有点意思了:
 
static void PlaceOrder(string name)
{
Thread thread1 = new Thread(new ThreadStart(Cooking));
thread1.Start();
}
static void Cooking()
{
Console.Write("开始制作");
}

运行程序, 你会发现输出结果是:

ScreenShot055

 

这是表示虽然厨师听到你的声音了,但是你坐在饭桌上的动作是在他开始做拉面之前. -- 更加的合情合理, 是吗?

我们还可以引入参数:


static void PlaceOrder(string name)
{
Thread thread1 = new Thread(t => Cooking(name));
thread1.Start();
}
static void Cooking(string name)
{
Console.WriteLine("开始制作" + name);
}

 

注意上面的参数的传递方法只用于.net 3.5/4

 

多线程

如果一个饭店有多个厨师, 并且同时有多个人点餐, 我们可以像这样模拟实现:



static void Main(string[] args)
{
string name = "兰州拉面";
int number = 5;
Console.WriteLine("来" + number + "碗" + name);
PlaceOrder(name, 5);
Console.WriteLine("坐在饭桌上....");
Console.Read();
}
static void PlaceOrder(string name, int number)
{

for (int i = 0; i < number; i++)
{
Thread thread1 = new Thread(t => Cooking(name));
thread1.Start();
}
}
static void Cooking(string name)
{
Console.WriteLine("开始制作" + name);
}

 

运行后, 结果显示:

ScreenShot057

 

嗯, 有些厨师动作还是快得像机器人, 让我们给他们一些休息的时间:

 


static void Cooking(string name)
{
Thread.Sleep(10);
Console.WriteLine("开始制作" + name);
}

 

再次运行程序, 结果是:

ScreenShot058

 

线程的关联性和独立性

线程的运作是相对独立的, 完成不同的工作. 但是它们却是共享进程内的资源.

做个实验:


static void PlaceOrder(string name, int number)
{
int[] array = new int[] {1000,500,300,500,1};
for (int i = 0; i < number; i++)
{

int time = array[i];
Thread thread1 = new Thread(t => Cooking(name, i,time));
thread1.Start();
}
}
static void Cooking(string name, int id, int time)
{
Thread.Sleep(10);
Console.WriteLine(id + "号开始制作" + name);
}

这里我们想给每一个厨师一个编号, 但是当把i 当中参数传递的时候, visual studio 会发出警告:

" Access To Modified Closure “.

这个是什么意思呢? 运行一下程序, 输出是:

 

ScreenShot059

 

发现在运行程序的时候, 错误的读取了厨师的编号, 这就是那个警告发出的原因: 因为线程们共享的名字 i 在不停的变化中, 我们没有办法控制一个特定线程运行时i 的值, -- 它们是相对独立的.

解决方案就是增加一个变量名存放值作为传递:


static void PlaceOrder(string name, int number)
{
int[] array = new int[] {1000,500,300,500,1};
for (int i = 0; i < number; i++)
{
int j = i;
int time = array[i];
Thread thread1 = new Thread(t => Cooking(name, j,time));
thread1.Start();
}
}
最后我们来看看, 线程中独立运行的实验:
 

static void PlaceOrder(string name, int number)
{
int[] array = new int[] {1000,500,300,500,1};
for (int i = 0; i < number; i++)
{
int j = i;
int time = array[i];
Thread thread1 = new Thread(t => Cooking(name, j,time));
thread1.Start();
}
}
static void Cooking(string name, int id, int time)
{
Thread.Sleep(10);
Console.WriteLine(id + "号开始制作" + name);
Thread.Sleep(time);
Console.WriteLine(id + "号准备完毕,花费时间:" + time);
}
每个厨师的速度是不一样的, 他们花费的时间不同, 所以先开始的不一定先完成, 上面的代码运行的结果是:
 

ScreenShot060

 

请仔细读读上面的代码和输出的结果, 应该大家都可以理解.

 

本文来自于喜乐的ASP.NET(Alex Song) 转贴请注明出处

posted @ 2011-10-29 06:08 拥有的都是恩典 阅读(...) 评论(...) 编辑 收藏