1. 程式人生 > >TLS執行緒區域性儲存--thread_specific_ptr

TLS執行緒區域性儲存--thread_specific_ptr

大多數函式都不是可重入的。這也就是說在某一個執行緒已經呼叫了一個函式時,如果你再呼叫同一個函式,那麼這樣是不安全的。一個不可重入的函式通過連續的呼叫來儲存靜態變數或者是返回一個指向靜態資料的指標。 舉例來說,std::strtok就是不可重入的,因為它使用靜態變數來儲存要被分割成符號的字串。有兩種方法可以讓不可重用的函式變成可重用的函式。第一種方法就是改變介面,用指標或引用代替原先使用靜態資料的地方。比方說,POSIX定義了strok_r,std::strtok中的一個可重入的變數,它用一個額外的char**引數來代替靜態資料。這種方法很簡單,而且提供了可能的最佳效果。但是這樣必須改變公共介面,也就意味著必須改程式碼。另一種方法不用改變公有介面,而是用本地儲存執行緒(thread local storage)來代替靜態資料(有時也被成為特殊執行緒儲存,thread-specific storage)。Boost執行緒庫提供了智慧指標boost::thread_specific_ptr來訪問本地儲存執行緒。每一個執行緒第一次使用這個智慧指標的例項時,它的初值是NULL,所以必須要先檢查這個它的只是否為空,並且為它賦值。Boost執行緒庫保證本地儲存執行緒中儲存的資料會線上程結束後被清除。List5是一個使用boost::thread_specific_ptr的簡單例子。其中建立了兩個執行緒來初始化本地儲存執行緒,並有10次迴圈,每一次都會增加智慧指標指向的值,並將其輸出到std::cout上(由於std::cout是一個共享資源,所以通過互斥體進行同步)。main執行緒等待這兩個執行緒結束後就退出。從這個例子輸出可以明白的看出每個執行緒都處理屬於自己的資料例項,儘管它們都是使用同一個boost::thread_specific_ptr。

#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/tss.hpp>
#include <iostream>
 
boost::mutex io_mutex;
boost::thread_specific_ptr<int> ptr;
 
struct count
{
        count(int id) : id(id) { }
        
        void operator()()
        {
                if (ptr.get() == 0)
                ptr.reset(new int(0));
                
                for (int i = 0; i < 10; ++i)
                {
                        (*ptr)++;
                        boost::mutex::scoped_lock
                        lock(io_mutex);
                        std::cout << id << ": "
                        << *ptr << std::endl;
                }
        }
        
        int id;
};
 
int main(int argc, char* argv[])
{
        boost::thread thrd1(count(1));
        boost::thread thrd2(count(2));
        thrd1.join();
        thrd2.join();
        return 0;
}