线程局部存储允许多线程应用程序为每个线程拥有给定数据项的单独实例。在单线程应用程序中使用静态或全局数据的情况下,这可能导致多线程应用程序中的争用、死锁或数据损坏。一个例子是 C errno
变量,用于存储与标准 C 库函数相关的错误代码。对于支持多线程应用程序的编译器来说,为每个线程提供单独的 errno
实例是一种常见的做法(POSIX 要求),以避免不同线程竞争读取或更新该值。
尽管编译器通常以声明语法的扩展形式提供此功能(例如 __declspec(thread)
或
对 thread
static
或命名空间范围变量声明的注解),但这种支持是非可移植的,并且通常在某些方面受到限制,例如仅支持 POD 类型。
boost::thread_specific_ptr
的可移植线程局部存储
boost::thread_specific_ptr
为线程局部存储提供了一种可移植的机制,该机制适用于 Boost.Thread 支持的所有编译器。boost::thread_specific_ptr
的每个实例都表示一个指向对象的指针(例如 errno
),其中每个线程都必须具有不同的值。可以使用 get()
成员函数或使用 *
和 ->
指针解引用运算符来获取当前线程的值。最初,指针在每个线程中都具有 NULL
值,但是可以使用 reset()
成员函数设置当前线程的值。
如果使用 reset()
更改了当前线程的指针值,则通过调用清理例程来销毁先前的值。或者,可以通过调用 release()
成员函数将存储的值重置为 NULL
并返回先前的值,从而允许应用程序重新负责销毁该对象。
当线程退出时,将销毁与每个 boost::thread_specific_ptr
实例关联的对象。默认情况下,指向指针 p
的对象通过调用 delete p
销毁,但是可以通过为构造函数提供清理例程来为 boost::thread_specific_ptr
的特定实例覆盖此操作。在这种情况下,通过调用 func(p)
销毁对象,其中 func
是提供给构造函数的清理例程。清理函数的调用顺序未指定。如果清理例程设置了与已清理的 boost::thread_specific_ptr
实例关联的值,则该值将添加到清理列表。当没有具有值的 boost::thread_specific_ptr
的未完成实例时,清理完成。
注意:在某些平台上,对于使用平台原生 API 创建的线程,不执行线程特定数据的清理。在这些平台上,除非从该线程手动调用 boost::on_thread_exit()
,否则此类清理仅针对使用 boost::thread
启动的线程完成。
Boost.Thread 使用 thread_specific_ptr
实例的地址作为线程特定指针的键。这避免了创建/销毁需要锁来防止竞争条件的键。这有一点性能责任,因为必须使用关联容器来完成访问。
// #include <boost/thread/tss.hpp> namespace boost { template <typename T> class thread_specific_ptr { public: thread_specific_ptr(); explicit thread_specific_ptr(void (*cleanup_function)(T*)); ~thread_specific_ptr(); T* get() const; T* operator->() const; T& operator*() const; T* release(); void reset(T* new_value=0); }; }
delete this->get()
是良构的。
构造一个 thread_specific_ptr
对象,用于存储指向类型为 T
的对象的指针,该对象特定于每个线程。默认的基于 delete
的清理函数将用于在调用 reset()
或线程退出时销毁任何线程局部对象。
如果发生错误,则抛出 boost::thread_resource_error
。
cleanup_function(this->get())
不会抛出任何异常。
构造一个 thread_specific_ptr
对象,用于存储指向类型为 T
的对象的指针,该对象特定于每个线程。当调用 reset()
或线程退出时,将使用提供的 cleanup_function
销毁任何线程局部对象。
如果发生错误,则抛出 boost::thread_resource_error
。
与此 thread_specific_ptr 关联的所有线程特定实例(可能除了与此线程关联的实例之外)都必须为空。
调用 this->reset()
以清理当前线程的关联值,并销毁 *this
。
无。
此要求是由于为了删除所有这些实例,实现应被迫维护具有关联特定 ptr 的所有线程的列表,这与线程特定数据的目标背道而驰。
![]() |
注意 |
---|---|
需要注意确保在 |
this->get()
无。
this->get
不为 NULL
。
*(this->get())
无。
如果 this->get()!=new_value
且 this->get()
不为 NULL
,则根据需要调用 delete this->get()
或 cleanup_function(this->get())
。将 new_value
存储为与当前线程关联的指针。
this->get()==new_value
如果发生错误,则抛出 boost::thread_resource_error
。
返回 this->get()
并存储 NULL
作为与当前线程关联的指针,而不调用清理函数。
this->get()==0
无。