原文地址:
Threading in C#
part 1 : 概念
当线程开始执行(thread.Start()
),线程IsAlive
属性为true
当线程构造函数传入的委托
执行完成,线程结束
一旦线程执行结束,不能 重新执行Start
- 线程安全
class ThreadSafe
{
static bool done;
static readonly object locker = new object();
static void Main()
{
new Thread (Go).Start();
Go();
}
static void Go()
{
lock (locker)
{
if (!done) { Console.WriteLine ("Done"); done = true; }
}
}
}
- 给线程传送数据
static void Main()
{
Thread t = new Thread ( () => Print ("Hello from t!") );
t.Start();
}
static void Print (string message)
{
Console.WriteLine (message);
}
线程如何工作
多线程由线程调度(thread scheduler)内部管理,线程调度(thread scheduler)程序是CLR委托给操作系统的函数。线程调度程序确保为所有ative的线程分配适当的执行时间,并且等待或阻止的线程(例如,在独占锁或用户输入上)不消耗CPU时间。
在单处理器计算机上,线程调度程序执行时间分片 - 在每个ative线程之间快速切换执行。在Windows下,时间片通常在几十毫秒的区域内 - 远大于实际切换一个线程与另一个线程之间的上下文中的CPU开销(通常在几微秒区域内)。
在多处理器计算机上,多线程是通过时间切片和真正并发的混合实现的,其中不同的线程在不同的CPU上同时运行代码。 几乎可以肯定,仍然会有一些时间切片,因为操作系统需要服务自己的线程 - 以及其他应用程序的线程。
当一个线程由于诸如时间分片之类的外部因素而被执行中断时,该线程被认为被抢占。 在大多数情况下,线程无法控制它被抢占的时间和地点。
Foreground and Background Threads
创建的线程默认是Foreground,Foreground线程保证应用程序alive。一旦所有的Foreground线程执行结束,应用也就退出。这时候如果还有Background线程在执行, Background线程会被终止。
线程优先级
线程的Priority属性决定该线程相对于操作系统中其他ative线程的执行时间
enum ThreadPriority { Lowest, BelowNormal, Normal, AboveNormal, Highest }
Thread Pooling
线程池通过共享和回收线程来减少每次创建线程时的开销,允许在非常精细的级别上应用多线程而不会降低性能。
线程池还会限制它将同时运行的工作线程总数。 过多的活动线程会对管理负担限制操作系统,并使CPU缓存无效。 达到限制后,作业将排队并仅在另一个完成时启动。 这使得任意并发应用程序成为可能,例如Web服务器。
使用池化线程(pooled threads)需要注意以下
- 无法设置池化线程的名称,使调试更加困难(尽管可以在Visual Studio的“线程”窗口中进行调试时附加说明)。
- 池化线程始终是后台线程(这通常不是问题)。
- Blocking 池化线程可能会在应用程序的早期生命周期中触发额外的延迟,除非你调用ThreadPool.SetMinThreads(请参阅优化线程池)。
- 可以自由更改池化线程的优先级 - 在释放回池时它将恢复正常。
可以通过以下几种方式使用ThreadPool
- Task Parallel Library (from Framework 4.0)
ThreadPool.QueueUserWorkItem
- asynchronous delegates
BackgroundWorker