修改BOOST(一)
boost是个不错的库。可是也不算太成熟。例如,boost的处理TLS是通过boost_threadmon.dll,使用了TLS的代码必须带一个动态链接库;其次库也不能自动安装,也不能根据你的程序选择了什么样的链接方式(如MT,MD)选择库,如果每次编写一个小型的测试程序都要设置很多东西,恐怕太费力气了;第三,缺乏一些常用的功能,如事件,读写锁等。今天我要设置的是使得你在VC下只需要设置MT或MD方式(链接到多线程动态链接和静态连接库)就可以使用boost。其次是将boost_threadmon.dll合并到libboost_thread.lib库中。『本人刚学boost才4天,说错了恐怕在所难免,请指正。本文中使用的版本为1.28.0』
boost多线程库包括两个,一个是boost_threadmon.dll,是个动态连接库,另一个为libboost_thread.lib,是个静态链接库。为什么要用两个呢?主要是为了清除TLS中的数据。在boost_threadmon.dll加载的时候,动态链接库收到消息DLL_PROCESS_ATTACH,这时它分配一个TLS和关键代码段CriticalSection。在用户程序创建线程的时候,收到DLL_THREAD_ATTACH,这时将该线程的TLS数据清除。当主程序退出的时候,收到DLL_PROCESS_DETACH,这时动态链接库清除主线程的TLS数据。
Boost管理TLS如下:当用户设置TLS数据时,boost将该数据指针和一个清理函数放置到一个cleanup_info的结构中,并将它设置到一个cleanup_handler的map中。cleanup_info第一个成员为清理函数指针,第二个成员为数据指针本身。而cleanup_handler则以TLS索引为key,以cleanup_info为data项内部的一个TLS索引对应着一个cleanup_handlers指针,而该指针中的数据都是用户分配的TLS和对应的数据指针以及释放函数。Boost又使用on_thread_exit(&cleanup)函数将cleanup_handlers安装到boost_threadmon.dll中的TLS索引上。
涉及的tss.cpp中的结构如下:
typedef std::pair<void(*)(void*), void*> cleanup_info;
typedef std::map<int, cleanup_info> cleanup_handlers;
涉及的threadmon.cpp中的结构如下:
typedef void (__cdecl * handler)(void);
typedef std::list<handler> exit_handlers;
typedef std::set<exit_handlers*> registered_handlers;
上面可能我根本没有说清楚,可是我不想再打太多的字了,下面直接修改:
1. Thread.hpp文件开头修改为:
#ifndef BOOST_THREAD_WEK070601_HPP
#define BOOST_THREAD_WEK070601_HPP
////////////////////////////////////////////////////////////////////////////
/*
·monitor库:使用/MT boost_mon_libmt.lib thread:boost_thread_libmt.lib
·monitor库:使用/MTD boost_mon_libmtd.lib thread:boost_thread_libmtd.lib
·monitor库:使用/MD boost_mon_libmd.lib thread:boost_thread_libmd.lib
·monitor库:使用/MDD boost_mon_libmdd.lib thread:boost_thread_libmdd.lib
·monitor-thread合并库:使用/MT boost_thread_mon_libmt.lib
·monitor-thread合并库:使用/MTD boost_thread_mon_libmtd.lib
·monitor-thread合并库:使用/MD boost_thread_mon_libmd.lib
·monitor-thread合并库:使用/MDD boost_thread_mon_libmdd.lib
*/
#ifdef WIN32
#ifndef _MT
#error ERROR: Must compiled with multithread dll!
#endif
#define BOOST_HAS_THREADS
#ifndef BOOST_THREADMON_AS_DLL
#ifdef _DEBUG
#ifdef _DLL
#pragma comment( lib, "boost_thread_mon_libmdd.lib")
#else
#pragma comment( lib, "boost_thread_mon_libmtd.lib")
#endif
#else
#ifdef _DLL
#pragma comment( lib, "boost_thread_mon_libmd.lib")
#else
#pragma comment( lib, "boost_thread_mon_libmt.lib")
#endif
#endif
#else
#ifdef _DEBUG
#ifdef _DLL
#pragma comment( lib, "boost_mon_libmdd.lib")
#pragma comment( lib, "boost_thread_libmdd.lib")
#else
#pragma comment( lib, "boost_mon_libmtd.lib")
#pragma comment( lib, "boost_thread_libmtd.lib")
#endif
#else
#ifdef _DLL
#pragma comment( lib, "boost_mon_libmd.lib")
#pragma comment( lib, "boost_thread_libmd.lib")
#else
#pragma comment( lib, "boost_mon_libmt.lib")
#pragma comment( lib, "boost_thread_libmt.lib")
#endif
#endif
#endif
#endif
//////////////////////////////////////////////////////////////////////////////////
#include <boost/config.hpp>
#ifndef BOOST_HAS_THREADS
# error Thread support is unavailable!
#endif
2. Threadmon.hpp文件修改为:
///////////////////////////////////////////////////////////////////////////
//2002.5.30修改。
#ifdef BOOST_THREADMON_AS_DLL
#ifdef BOOST_THREADMON_EXPORTS
#define BOOST_THREADMON_API __declspec(dllexport)
#else
#define BOOST_THREADMON_API __declspec(dllimport)
#endif
#else
#define BOOST_THREADMON_API
#endif
extern "C" BOOST_THREADMON_API int on_thread_exit(void (__cdecl * func)(void));
extern "C" BOOST_THREADMON_API void on_thread_detach();
3. Threadmon.cpp文件修改为:
///////////////////////////////////////////////////////////////////
//This File has been modified!
// threadmon.cpp : Defines the entry point for the DLL application.
//
////////////////////////////////////////////////////////
//2002.5.30.modified.
#ifdef BOOST_THREADMON_AS_DLL
#define BOOST_THREADMON_EXPORTS
#else
#include <boost/thread/once.hpp>
#endif//BOOST_THREADMON_AS_DLL
////////////////////////////////////////////////////////
#include "threadmon.hpp"
#ifdef BOOST_HAS_WINTHREADS
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include <windows.h>
#ifdef BOOST_MSVC
# pragma warning(disable : 4786)
#endif
#include <list>
#include <set>
#include <algorithm>
typedef void (__cdecl * handler)(void);
typedef std::list<handler> exit_handlers;
typedef std::set<exit_handlers*> registered_handlers;
namespace
{
CRITICAL_SECTION cs;
DWORD key;
registered_handlers registry;
}
void on_process_attach()
{
InitializeCriticalSection(&cs);
key = TlsAlloc();
}
void on_process_detach()
{
on_thread_detach();
// Destroy any remaining exit handlers. Above we assumed there'd only be the main
// thread left, but to insure we don't get memory leaks we won't make that assumption
// here.
EnterCriticalSection(&cs);
for (registered_handlers::iterator it = registry.begin();
it != registry.end(); ++it)
{
#ifndef BOOST_THREADMON_AS_DLL
for (exit_handlers::iterator p = (*it)->begin(); p != (*it)->end(); ++p)
(*p)();
#endif
delete (*it);
}
LeaveCriticalSection(&cs);
DeleteCriticalSection(&cs);
TlsFree(key);
}
#ifdef BOOST_THREADMON_AS_DLL
#if defined(__BORLANDC__)
#define DllMain DllEntryPoint
#endif
extern "C"
BOOL WINAPI DllMain(HANDLE module, DWORD reason, LPVOID)
{
switch (reason)
{
case DLL_PROCESS_ATTACH:
on_process_attach();
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
on_thread_detach();
break;
case DLL_PROCESS_DETACH:
on_process_detach();
break;
}
return TRUE;
}
#else//BOOST_THREADMON_AS_DLL
boost::once_flag once = BOOST_ONCE_INIT;
class process_envelope
{
process_envelope()
{
boost::call_once(&on_process_attach, once);
}
public:
~process_envelope(){on_process_detach();}
static process_envelope *get()
{
static process_envelope p;
return &p;
}
};
#endif//!BOOST_THREADMON_AS_DLL
void on_thread_detach()
{
// Call the thread's exit handlers.
#ifndef BOOST_THREADMON_AS_DLL
process_envelope::get();
#endif
exit_handlers* handlers = static_cast<exit_handlers*>(TlsGetValue(key));
if (handlers)
{
for (exit_handlers::iterator it = handlers->begin(); it != handlers->end(); ++it)
(*it)();
// Remove the exit handler list from the registered lists and then destroy it.
EnterCriticalSection(&cs);
registry.erase(handlers);
LeaveCriticalSection(&cs);
delete handlers;
}
}
int on_thread_exit(void (__cdecl * func)(void))
{
#ifndef BOOST_THREADMON_AS_DLL
process_envelope::get();
#endif
// Get the exit handlers for the current thread, creating and registering
// one if it doesn't exist.
exit_handlers* handlers = static_cast<exit_handlers*>(TlsGetValue(key));
if (!handlers)
{
try
{
handlers = new exit_handlers;
// Handle "broken" implementations of operator new that don't throw.
if (!handlers)
return -1;
}
catch (...)
{
return -1;
}
// Attempt to set a TLS value for the new handlers.
if (!TlsSetValue(key, handlers))
{
delete handlers;
return -1;
}
// Attempt to register this new handler so that memory can be properly
// cleaned up.
try
{
EnterCriticalSection(&cs);
registry.insert(handlers);
LeaveCriticalSection(&cs);
}
catch (...)
{
LeaveCriticalSection(&cs);
delete handlers;
return -1;
}
}
// Attempt to add the handler to the list of exit handlers. If it's been previously
// added just report success and exit.
try
{
handlers->push_front(func);
}
catch (...)
{
return -1;
}
return 0;
}
#endif // BOOST_HAS_WINTHREADS
4. Thread.cpp文件修改为:
在#include "timeconv.inl"行后:
////////////////////////////////////////////////////////////////////////
//2002.5.30;修改
#ifdef WIN32
#ifndef BOOST_THREADMON_AS_DLL
#include "threadmon.hpp"
#endif
#endif
////////////////////////////////////////////////////////////////////////
修改thread_proxy(void* param)方法的尾部为:
////////////////////////////////////////////////////////////////////////
//2002.5.30;修改
#ifdef WIN32
#ifndef BOOST_THREADMON_AS_DLL
on_thread_detach();
#endif
#endif
////////////////////////////////////////////////////////////////////////
5. 将<boost>\libs\thread\src目录下的所有文件插入到自己新建的工程中,按上面的thread.hpp头文件中的库名分别生成不同的库文件,将这些库文件拷贝到VC目录下,以后编译使用了boost.thread的工程时,再也不需要任何设置了。