boost庫中thread多線程中的thread_specific_ptr

       大多數函數都不是可重入的。這也就是說在某一個線程已經調用了一個函數時,如果你再調用同一個函數,那麼這樣是不安全的。舉例來說,std::strtok就是不可重入的,因爲它使用靜態變量來保存要被分割成符號的字符串。

       一個不可重入的函數通過連續的調用來保存靜態變量或者是返回一個指向靜態數據的指針,有兩種方法可以讓不可重用的函數變成可重用的函數。

       方法1:就是改變接口,用指針或引用代替原先使用靜態數據的地方。比方說,POSIX定義了strok_r,std::strtok中的一個可重入的變量,它用一個額外的char**參數來代替靜態數據。這種方法很簡單,而且提供了可能的最佳效果。但是這樣必須改變公共接口,也就意味着必須改代碼。

        方法2:不用改變公有接口,而是用本地存儲線程(Thread-Locally Storage)來代替靜態數據(有時也被成爲特殊線程存儲,thread-specific storage)。

       Boost線程庫提供了智能指針boost::thread_specific_ptr來訪問本地存儲線程。thread_specific_ptr線程局部存儲的包裝,它可用於封裝線程獨立的全局變量。每一個線程第一次使用這個智能指針的實例時,它的初值是NULL(所以必須要先檢查這個它的值是否爲空),在每個線程使用它之前需要new一個對象交給全局的threah_specific_ptr進行管理,當線程退出後,Boost線程庫保證本地存儲線程中保存的數據會在線程結束後被清除,這樣,各個線程就可以各自獨立地訪問這個全局變量的本地存儲版本,線程之間就不會因爲訪問同一全局對象而引起資源競爭導致性能下降。而線程結束時,這個資源會被自動釋放。

它可以應用在以下兩種場景:

       1. 改編一個原本設計用於單線程的庫接口,比如libc裏的strtok函數。這種庫一般隱含的使用一個全局變量,可以使用thread_specific_ptr控制全局變量,使其可用於多線程。
       2. 線程中使用了一系列的方法/函數,它們需要一個邏輯上的全局變量來共享數據,但實際上這個變量是線程獨立的。

thread_specific_ptr代表了某個全局變量的本地存儲,各個線程可以各自獨立地通過它訪問這個全局變量的本地副本,起到了井水不犯河水的效果。

使用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;
}

其中創建了兩個線程來初始化本地存儲線程,並有10次循環,每一次都會增加智能指針指向的值,並將其輸出到std::cout上(由於std::cout是一個共享資源,所以通過互斥體進行同步)。main線程等待這兩個線程結束後就退出。從這個例子輸出可以明白的看出每個線程都處理屬於自己的數據實例,儘管它們都是使用同一個boost::thread_specific_ptr。

參考:

https://blog.csdn.net/liujiayu2/article/details/50587084

https://blog.csdn.net/flyingleo1981/article/details/47083737

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章