提到线程时,经常被提及的另外一个概念是进程,而且这也是很多C#学习书籍乐于讨论的两个话题。所谓进程,比较合理的定义是一段静态指令序列(程序)的动态执行过程,是系统进行系统分配和调度的一个基本单位。简单理解,就是在计算机上运行的程序,我们可以通过任务管理器看到当前计算机运行的程序或者进程。一个进程中又可以包含若干个独立的执行流,我们将这些执行流称为线程,线程是CPU调度和分配的基本单位。每个线程都有自己的专有寄存器(栈指针、程序计数器等,不了解这些没啥关系),但代码区是共享的,也就是说不同的线程可以执行同样的函数。多线程是指程序中包含多个执行流,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。例如我们非常熟悉的QQ,每个运行的QQ就是一个进程,而用一个QQ和多个人进行聊天,就是在使用多线程,每一个聊天窗口就是一个线程,里面可以包含相同的函数,比如说表情等。下图是计算机里的进程:
与线程相关的另外一个概念是软件的并行性,并行性的主要特点是并发处理。对单处理器的计算机来说,单个CPU在任何时候只能执行一个线程。在一个单处理器系统中,操作系统可以通过分时处理来获得并发,在这种情况下,系统为每个线程分配一个CPU时间片,每个线程只能在分配的时间片内才拥有对CPU的控制权,其他时间在等待,即同一时间永远只有一个线程在运行,由于系统为每个线程划分的时间片很少(20毫秒左右),所以在用户看来,好像是多个线程在同时运行,实际上,一个线程执行了一个时间单元后,另外一个线程接着执行下一个时间单元,如此反复,这就是并发。而现在很多电脑都是多核,也就是多个CPU,那么就会出现多任务操作系统同时管理多个进程运行,简单说当总线程<=CPU数量:并行运行;当总线程>=CPU数量:并发运行;简单解释一下,有兴趣的同学可以百度。
多线程一般多使用在网络环境下,这是因为在C/S模式下,服务器需要不断监听来自不同客户端的请求,如果采用单线程机制的话,服务器将无法处理其他事情,因为这个线程要不断地监听请求而无暇对其他请求做出相应。
当要花费大量时间进行连续的操作时,或者等待网络或其他I/O设备响应时,就可以使用多线程技术。
在我们使用visual studio 软件创建的每一个C#程序中,都有一个主线程,也就是Main()函数,如果我们使用Thread类创建一个线程,那么这个程序中就会含有两个线程,一个主线程和另外一个通过Thread类创建的线程。当然,我们可以在这个程序中另外添加很多的线程,已达到“多”的线程,但这么做需要考虑实际的需要。线程一多,第一不利于管理,第二容易出现很多bug,例如数据竞争等问题。如下例:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace TestThread
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Starting...");
Thread thread = new Thread(PrintNumbers);
thread.Start();
}
static void PrintNumbers()
{
for(int i = 0; i < 10; i++)
{
Console.Write(i+ " ");
}
}
}
}
运行结果如下图所示: