System.Threading.Interlocked
类库: 为多个线程共享的变量提供原子操作。
线程池
ThreadPool
类为应用程序提供一个由系统管理的辅助线程池。如果需要处理的短期任务,则可以使用线程池这种便捷的方式
不适用线程池的情况
-
需要前台线程。
-
需要使线程具有特定的优先级。
-
您的任务会导致线程长时间被阻塞。 由于线程池具有最大线程数限制,因此大量阻塞的线程池线程可能会阻止任务启动。
-
需要将线程放入单线程单元。 所有 ThreadPool 线程均处于多线程单元中。
-
您需要具有与线程关联的稳定标识,或使某一线程专用于某一任务。
线程池的特征
线程池线程都是后台线程。每个线程都都使用默认堆栈大小,默认的优先级,并处于多线程单元中。每个进程只有一个线程池对象。
线程池中的异常
线程池线程中未经处理的异常将终止进程。以下三种情况例外:
-
由于调用
Abort
,线程池中将引发ThreadAbortException
-
由于正在卸载应用程序域,线程池线程将引发
AppDomainUnloadedException
-
公共语言运行时或宿主进程将终止线程
最大线程池数
可排队到线程池的操作数仅受可用内存的限制;但是,线程池限制进程中可同时处于活动状态的线程数。通过使用 GetMaxThreads
和 SetMaxThreads
方法可以控制最大线程数。
说明:线程池会创建和销毁工作线程以优化吞吐量,吞吐量定义为单位时间内完成的任务数。 线程过少时可能无法更好地利用可用资源,但线程过多时又可能会加剧资源的争用情况。
跳过安全检查
线程池还提供了 ThreadPool.UnsafeQueueUserWorkItem
和 ThreadPool.UnsafeRegisterWaitForSingleObject
方法。 仅在确定调用方的堆栈与执行排队任务的过程中执行的任何安全检查无关时使用这些方法。 QueueUserWorkItem
和 RegisterWaitForSingleObject
都捕获调用方的堆栈,在线程开始执行任务时将此堆栈合并到线程池线程的堆栈中。 如果需要进行安全检查,则必须检查整个堆栈。 尽管此检查提供了安全,但它还具有一定的性能开销。
使用 RegisterWaitForSingleObject
namespace MyConsole2
{
class Program
{
static object o = new object();
static void Main(string[] args)
{
// 通知正在等待的线程已发生非终止事件
AutoResetEvent ev = new AutoResetEvent(false);
TaskInfo ti = new TaskInfo();
ti.OtherInfo = "First task";
ti.Handle = ThreadPool.RegisterWaitForSingleObject(
ev,//watihandler
new WaitOrTimerCallback(WaitProc),//当超时或者waithandler终止时调用
ti,//传递的参数
1000,//超时时间
true //调用委托后将不再waithandler上等待,fale:每次完成等待操作后重置计时器,直到注销等待
);
// Thread.Sleep(3100);
Console.WriteLine("Main thread signals.");
// ev.Set();
Thread.Sleep(1000);
Console.ReadLine();
}
public static void WaitProc(object state, bool timedOut)
{
TaskInfo ti = (TaskInfo)state;
string cause = "TIMED OUT";
if (!timedOut)
{
cause = "SIGNALED";
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
);
}
}
public class TaskInfo
{
public RegisteredWaitHandle Handle = null;
public string OtherInfo = "default";
}
}