不可不知的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);
}
static void PlaceOrder(string name)
{
Thread thread1 = new Thread(new ThreadStart(Cooking));
thread1.Start();
}
static void Cooking()
{
Console.Write("开始制作");
}
运行程序, 你会发现输出结果是:
这是表示虽然厨师听到你的声音了,但是你坐在饭桌上的动作是在他开始做拉面之前. -- 更加的合情合理, 是吗?
我们还可以引入参数:
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);
}
运行后, 结果显示:
嗯, 有些厨师动作还是快得像机器人, 让我们给他们一些休息的时间:
static void Cooking(string name)
{
Thread.Sleep(10);
Console.WriteLine("开始制作" + name);
}
再次运行程序, 结果是:
线程的关联性和独立性
线程的运作是相对独立的, 完成不同的工作. 但是它们却是共享进程内的资源.
做个实验:
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 “.
这个是什么意思呢? 运行一下程序, 输出是:
发现在运行程序的时候, 错误的读取了厨师的编号, 这就是那个警告发出的原因: 因为线程们共享的名字 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);
}
请仔细读读上面的代码和输出的结果, 应该大家都可以理解.
本文来自于喜乐的ASP.NET(Alex Song) 转贴请注明出处