进程(英语:process),是计算机中已运行程序的实体。在面向进程设计的系统(如早期的 UNIX,Linux 2.4 及更早的版本)中,进程是程序的基本执行实体;在面向线程设计的系统中,进程本身不是基本运行单位,而是线程的容器。程序本身只是指令、数据及其组织形式的描述,进程才是程序(那些指令和数据)的真正运行实例。
用户下达运行程序的命令后,就会产生进程。同一程序可产生多个进程(一对多关系),以允许同时有多位用户运行同一程序,却不会相冲突。
每个进程中至少包含一个线程,这个线程叫做主线程
线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
同一进程中的多条线程将共享该进程中的全部系统资源,如虚拟地址空间,文件描述符和信号处理等等。但同一进程中的多个线程有各自的调用栈(call stack),自己的寄存器环境(register context),自己的线程本地存储(thread-local storage)。
一个进程可以有很多线程,每条线程并行执行不同的任务。
多线程(英语:multithreading),是指从软件或者硬件上实现多个线程并发执行的技术。
软件多线程:即便处理器只能运行一个线程,操作系统也可以通过快速的在不同线程之间进行切换,由于时间间隔很小,来给用户造成一种多个线程同时运行的假象。
每次创建一个线程,需要分配和初始化一个内核对象,也需要分配和初始化线程的堆栈空间;当线程终止时,线程的堆栈空间被释放,内核对象亦被释放(如果其使用数达到 0)。因此,与创建和销毁线程相关的许多开销都和创建线程原本要执行的工作无关。
当 CLR 初始化时,其线程池中不含有线程。当应用程序要创建线程来执行任务时,该应用程序应请求线程池线程来执行任务。线程池知道后将创建一个初始线程。该新线程经历的初始化和其他线程一样;但是任务完成后,该线程不会自行销毁。相反,它会以挂起状态返回线程池。如果应用程序再次向线程池发出请求,那么这个挂起的线程将激活并执行任务,而不会创建新线程。这节约了很多开销。只要线程池中应用程序任务的排队速度低于一个线程处理每项任务的速度,那么就可以反复重用同一线程,从而在应用程序生存期内节约大量开销。
那么,如果线程池中应用程序任务排队的速度超过一个线程处理任务的速度,则线程池将创建额外的线程。当然,创建新线程确实会产生额外开销,但应用程序在其生存期中很可能只请求几个线程来处理交给它的所有任务。因此,总体来说,通过使用线程池可以提高应用程序的性能。
线程池的一个绝妙特性是:它是启发式的。如果您的应用程序需要执行很多任务,那么线程池将创建更多的线程。如果您的应用程序的工作负载逐渐减少,那么线程池线程将自行终止。线程池的算法确保它仅包含置于其上的工作负荷所需要的线程数!
线程池可以提供四种功能:
使用 System.Threading 命名空间中定义的 ThreadPool 类。ThreadPool 类只提供静态方法,且不能构造它的实例。要让线程池线程异步调用方法,必须调用一个 ThreadPool 的重载 QueueUserWorkItem 方法,如下所示:
- public static Boolean QueueUserWorkItem(WaitCallback wc, Object state);
- public static Boolean QueueUserWorkItem(WaitCallback wc);
没有状态参数的 QueueUserWorkItem 版本将 null 传递给回调方法。最后,池中的某些线程将调用您的方法来处理该工作项。您编写的回调方法必须与 System.Threading.WaitCallback 委托类型相匹配,其定义如下:
- public delegate void WaitCallback(Object state);
如果应用程序需要在某一时间执行某项任务,或者应用程序需要定期执行某些方法,那么使用线程池将是最佳选择。System.Threading 命名空间定义 Timer 类。当构造 Timer 类的实例时,是在告诉线程池您想在将来的某个特定时间回调自己的某个方法。Timer 类有四种构造函数:
- public Timer(TimerCallback callback, Object state, Int32 dueTime, Int32 period);
- public Timer(TimerCallback callback, Object state, UInt32 dueTime, UInt32 period);
- public Timer(TimerCallback callback, Object state, Int64 dueTime, Int64 period);
- public Timer(TimerCallback callback, Object state, Timespan dueTime, TimeSpan period);
所有这四种构造函数构造完全相同的 Timer 对象。回调参数标识您想由线程池线程回调的方法。当然,您编写的回调方法必须与 System.Threading.TimerCallback 委托类型相匹配,其定义如下:
- public delegate void TimerCallback(Object state);
构造函数的状态参数允许您将状态数据传递给回调方法;如果没有要传递的状态数据,您可以传递 null。使用 dueTime 参数可以告诉线程池在第一次调用您的回调方法之前需要等待多少毫秒。可以利用一个有符号或无符号的 32 位值、一个有符号的 64 位值,或者一个 TimeSpan 值来指定毫秒数。如果您想立即调用回调方法,那么请将 dueTime 参数指定为 0。最后一个参数 period 允许您指定在每次连续调用之前需要等待的时间,单位为毫秒。如果您将 0 传递给这个参数,那么线程池将仅调用该回调方法一次。
构造 Timer 对象后,线程池知道要做什么,并自动为您监视时间。然而,Timer 类还提供了几种其他的方法,允许您与线程池进行通信,以便更改什么时候(或者是否)应当回调方法。具体地说,Timer 类提供了几种 Change 和 Dispose 方法:
- public Boolean Change(Int32 dueTime, Int32 period);
- public Boolean Change(UInt32 dueTime, UInt32 period);
- public Boolean Change(Int64 dueTime, Int64 period);
- public Boolean Change(TimeSpan dueTime, TimeSpan period);
- public Boolean Dispose();
- public Boolean Dispose(WaitHandle notifyObject);
Change 方法允许您更改 Timer 对象的 dueTime 和 period。Dispose 方法允许您在所有挂起的回调已经完成的时候,完全取消回调,并可选地用信号通知由 notifyObject 参数标识的内核对象。
Microsoft 研究人员在做性能研究时发现,许多应用程序生成线程,只是为了等待某单个内核对象得到信号通知。一旦该对象得到信号通知,这个线程就将某种通知发送给另一个线程,然后环回,等待该对象再次发出信号。有些开发人员编写的代码中甚至有几个线程,而每个线程都在等待一个对象。这是系统资源的巨大浪费。因此,如果当前您的应用程序中有多个线程在等待单个内核对象得到信号通知,那么线程池仍将是您提高应用程序性能的最佳资源。
要让线程池线程在内核对象得到信号通知时调用您的回调方法,您可以再次利用 System.Threading.ThreadPool 类中定义的一些静态方法。要让线程池线程在内核对象得到信号通知时调用方法,您的代码必须调用一个重载的 RegisterWaitHandle 方法。
当您调用这些方法之一时,h 参数标识出您想要线程池等待的内核对象。由于该参数是抽象基类 System.Threading.WaitHandle,因此您可以指定从该基类派生出来的任何类。特别地,您可以将一个引用传递给 AutoResetEvent、ManualResetEvent 或 Mutex object。第二个参数 callback 标识出您想要线程池线程调用的方法。您实现的回调方法必须与 System.Threading.WaitOrTimerCallback 委托类型相匹配,其定义如下列代码行所示:
- public delegate void WaitOrTimerCallback(Object state, Boolean timedOut);
第三个参数 state 允许您指定应传递给回调方法的某些状态数据,如果没有特别的状态数据要传递,则传递 null。第四个参数 milliseconds 允许您告诉线程池内核对象得到信号通知前应该等待的时间。这里通常传递 -1,以表示无限超时。如果最后一个参数 executeOnlyOnce 为真,那么线程池线程将仅执行回调方法一次。但是,如果 executeOnlyOnce 为假,那么线程池线程将在内核对象每次得到信号通知时执行回调方法。这对 AutoResetEvent 对象非常有用。
当调用回调方法时,会传递给它状态数据和 Boolean 值 timedOut。如果 timedOut 为假,则该方法知道它被调用的原因是内核对象得到信号通知。如果 timedOut 为真,则该方法知道它被调用的原因是内核对象在指定时间内没有得到信号通知。回调方法应该执行所有必需的操作。
在前面所示的原型中,您会注意到 RegisterWaitForSingleObject 方法返回一个 RegisteredWaitHandle 对象。该对象确定线程池在等待的内核对象。如果由于某种原因,您的应用程序要告诉线程池停止监视已注册的等待句柄,那么您的应用程序就可以调用 RegisteredWaitHandle 的 Unregister 方法:
- public Boolean Unregister(WaitHandle waitObject);
waitObject 参数表明当执行完队列中的所有工作项后,您想如何得到信号通知。如果不想得到信号通知,那么您应将 null 传递给该参数。如果您将一个有效引用传递给 WaitHandle-derived 对象,那么线程池会在已注册等待句柄的所有挂起工作项执行完后,通知该对象。
- namespace ThreadDemo_001
- {
- public class TaskInfo
- {
- public RegisteredWaitHandle Handle = null;
- public string OtherInfo = "default";
- }
- public class Example
- {
- public static void Main(string[] args)
- {
- // The main thread uses AutoResetEvent to signal the
- // registered wait handle, which executes the callback
- // method.
- AutoResetEvent ev = new AutoResetEvent(false);
- TaskInfo ti = new TaskInfo();
- ti.OtherInfo = "First task";
- // The TaskInfo for the task includes the registered wait
- // handle returned by RegisterWaitForSingleObject. This
- // allows the wait to be terminated when the object has
- // been signaled once (see WaitProc).
- ti.Handle = ThreadPool.RegisterWaitForSingleObject(
- ev,
- new WaitOrTimerCallback(WaitProc),
- ti,
- 1000,
- false
- );
- // The main thread waits three seconds, to demonstrate the
- // time-outs on the queued thread, and then signals.
- Thread.Sleep(TimeSpan.FromSeconds(30));
- Console.WriteLine("Main thread signals.");
- ev.Set();
- // The main thread sleeps, which should give the callback
- // method time to execute. If you comment out this line, the
- // program usually ends before the ThreadPool thread can execute.
- Thread.Sleep(1000);
- // If you start a thread yourself, you can wait for it to end
- // by calling Thread.Join. This option is not available with
- // thread pool threads.
- }
- // The callback method executes when the registered wait times out,
- // or when the WaitHandle (in this case AutoResetEvent) is signaled.
- // WaitProc unregisters the WaitHandle the first time the event is
- // signaled.
- public static void WaitProc(object state, bool timedOut)
- {
- // The state object must be cast to the correct type, because the
- // signature of the WaitOrTimerCallback delegate specifies type
- // Object.
- TaskInfo ti = (TaskInfo)state;
- string cause = "TIMED OUT";
- if (!timedOut)
- {
- cause = "SIGNALED";
- // If the callback method executes because the WaitHandle is
- // signaled, stop future execution of the callback method
- // by unregistering the WaitHandle.
- if (ti.Handle != null)
- ti.Handle.Unregister(null);
- }
- Console.WriteLine("WaitProc( {0} ) executes on thread {1}; cause = {2}.",
- ti.OtherInfo,
- Thread.CurrentThread.GetHashCode().ToString(),
- cause
- );
- }
- }
- }
来源: http://www.cnblogs.com/passlogs/p/6992757.html