在单线程程序中,这是一个完美的实现。但在多线程中,这就是个灾难了,想象一下多个线程访问它,并把异常对象保存在里面的情景吧。由于每个线程都有自己的堆栈和异常处理链,我们需要一个线程安全的get_exception_storage实现:每个线程都有自己单独的exception_storage,它在线程启动时被创建,并在结束时被销毁。Windows提供的线程局部存储(thread local storage,TLS)可以满足这个要求,它能让每个线程通过一个全局键值来访问为这个线程所私有的对象副本,这是通过TlsGetValue()和TlsSetValue这两个API来完成的。 Excptstorage.cpp中给出了get_exception_storage()函数的实现。它会被编译成动态链接库,因为我们可以籍此知道线程的创建和退出——系统在这两种情况下都会调用所有(当前进程加载的)dll的DllMain()函数,这让我们有机会创建特定于线程的数据,也就是exception_storage对象。
//excptstorage.cpp#include "excptstorage.h"#include <windows.h>namespace{ DWORD dwstorage;}namespace my_handler{ __declspec(dllexport) exception_storage* get_exception_storage() throw () { void * p = TlsGetValue(dwstorage); return reinterpret_cast <exception_storage*>(p); }}BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ){ using my_handler::exception_storage; exception_storage *p; switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: //主线程(第一个线程)不会收到DLL_THREAD_ATTACH通知,所以, //与其相关的操作也放在这了 dwstorage = TlsAlloc(); if (-1 == dwstorage) return FALSE; p = new exception_storage(); TlsSetValue(dwstorage, p); break ; case DLL_THREAD_ATTACH: p = new exception_storage(); TlsSetValue(dwstorage, p); break; case DLL_THREAD_DETACH: p = my_handler::get_exception_storage(); delete p; break ; case DLL_PROCESS_DETACH: p = my_handler::get_exception_storage(); delete p; break ; } return TRUE;}