进程(Process)是Windows系统中的一个基本概念,它包含着一个运行程序所需要的资源。一个正在运行的应用程序在操作系统中被视为一个进程,进程可以包括一个或多个线程。线程是操作系统分配处理器时间的基本单元,在进程中可以有多个线程同时执行代码。进程之间是相对独立的,一个进程无法访问另一个进程的数据(除非利用分布式计算方式),一个进程运行的失败也不会影响其他进程的运行,Windows系统就是利用进程把工作划分为多个独立的区域的。进程可以理解为一个程序的基本边界。是应用程序的一个运行例程,是应用程序的一次动态执行过程。
线程(Thread)是进程中的基本执行单元,是操作系统分配CPU时间的基本单位,一个进程可以包含若干个线程,在进程入口执行的第一个线程被视为这个进程的主线程。在.NET应用程序中,都是以Main()方法作为入口的,当调用此方法时系统就会自动创建一个主线程。线程主要是由CPU寄存器、调用栈和线程本地存储器(Thread Local Storage,TLS)组成的。CPU寄存器主要记录当前所执行线程的状态,调用栈主要用于维护线程所调用到的内存与数据,TLS主要用于存放线程的状态信息。
创建线程的一种简单方式是定义一个委托,并异步调用它。委托是方法的类型安全的引用。Delegate类 还支持异步地调用方法。在后台,Delegate类会创建一个执行任务的线程。
接下来定义一个方法,使用委托异步调用(开启一个线程去执行这个方法)static int TakesAWhile(int data,int ms){
Console.WriteLine("TakesAWhile started!");
Thread.Sleep(ms);//程序运行到这里的时候会暂停ms毫秒,然后继续运行下一语句
Console.WriteLine("TakesAWhile completed");
return ++data;
}
public delegate int TakesAWhileDelegate(int data,int ms);// 声明委托
static void Main(){
TakesAWhileDelegate d1 = TakesAWhile;
IAsyncResult ar = d1.BeginInvoke(1,3000,null,null);
while(ar.IsCompleted ==false ){
Console.Write(".");
Thread.Sleep(50);
}
int result = d1.EndInvoke(ar);
Console.WriteLine("Res:"+result);
}
代码来自siki老师
当我们通过BeginInvoke开启一个异步委托的时候,返回的结果是IAsyncResult,我们可以通过它的AsyncWaitHandle属性访问等待句柄。这个属性返回一个WaitHandler类型的对象,它中的WaitOne()方法可以等待委托线程完成其任务,WaitOne方法可以设置一个超时时间作为参数(要等待的最长时间),如果发生超时就返回false。
static void Main(){
TakesAWhileDelegated1 = TakesAWhile;
IAsyncResultar = d1.BeginInvoke(1,3000,null,null);
while(true){
Console.Write(".");
if(ar.AsyncWaitHanle.WaitOne(50,false)){
Console.WriteLine("Canget result now");
break;
}
}
intresult = d1.EndInvoke(ar);
Console.WriteLine("Res:"+result);
}//代码来自SIKI老师
等待委托的结果的第3种方式是使用异步回调。在BeginInvoke的第三个参数中,可以传递一个满足AsyncCallback委托的方法,AsyncCallback委托定义了一个IAsyncResult类型的参数其返回类型是void。对于最后一个参数,可以传递任意对象,以便从回调方法中访问它。(我们可以设置为委托实例,这样就可以在回调方法中获取委托方法的结果)
static void Main(){
TakesAWhileDelegate d1 = TakesAWhile;
d1.BeginInvoke(1,3000,TakesAWhileCompleted,d1);
while(true){
Console.Write(".");
Thread.Sleep(50);
}
}
static void TakesAWhileCompleted(IAsyncResult ar){//回调方法是从委托线程中调用的,并不是从主线程调用的,可以认为是委托线程最后要执行的程序
if(ar==null) throw new ArgumentNullException("ar");
TakesAWhileDelegate d1 = ar.AsyncState as TakesAWhileDelegate;
int result = d1.EndInvoke(ar);
Console.Write("Res:"+result);
}
使用Thread类可以创建和控制线程。Thread构造函数的参数是一个无参无返回值的委托类型。
static void Main(){
vart1 = new Thread(ThreadMain);
t1.Start();
Console.WriteLine("Thisis the main thread.");
}
static void ThreadMain(){
Console.WriteLine("Runningin a thread.");
}
在这里哪个先输出是无法保证了线程的执行有操作系统决定,只能知道Main线程和分支线程是同步执行的。在这里给Thread传递一个方法,调用Thread的Start方法,就会开启一个线程去执行,传递的方法。
创建线程需要时间。 如果有不同的小任务要完成,就可以事先创建许多线程 ,在应完成这些任务时发出请求。 这个线程数最好在需要更多的线程时增加,在需要释放资源时减少。
不需要 自己创建线程池,系统已经有一个ThreadPool类管理线程。这个类会在需要时增减池中线程的线程数,直到达到最大的线程数。 池中的最大线程数是可配置的。 在双核 CPU中 ,默认设置为1023个工作线程和 1000个I/o线程。也可以指定在创建线程池时应立即启动的最小线程数,以及线程池中可用的最大线程数。如果有更多的作业要处理,线程池中线程的个数也到了极限,最新的作业就要排队,且必须等待线程完成其任务。
static void Main(){
int nWorkerThreads;
int nCompletionPortThreads;
ThreadPool.GetMaxThreads(out nWorkerThreads,out nCompletionPortThreads);
Console.WriteLine("Max worker threads : " +nWorkerThreads+" I/O completion threads :"+nCompletionPortThreads );
for(int i=0;i<5;i++){
ThreadPool.QueueUserWorkItem(JobForAThread);
}
Thread.Sleep(3000);
}
static void JobForAThread(object state){
for(int i=0;i<3;i++){
Console.WriteLine("Loop "+i+" ,running in pooled thread "+Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(50);
}
}