一個函數可重入是指該函數能夠被多個線程同時調用。大多數函數都不是可重如的,由於不少函數會修改靜態數據結構裏的內容,若是多個線程同時調用,勢必破壞共享的靜態結構。能夠在不改變公共接口的狀況下,將一個非重入函數修改成可重入函數。思想是使用線程的本地存儲來實現,而boost::thread_specific_ptr正好提供了使用TLS(thread local storage)的機制。ios
在caffe框架中,class Caffe是一個單例類,這個類是能夠重入的,便可以被多個線程同時使用:git
進入到上圖109行的Get()函數:github
這個函數是一個static的函數,它的返回值是Caffe對象的引用,第13行定義了一個指向Caffe對象的智能指針,類型爲boost::thread_specific_ptr<Caffe>.代碼的16行首先判斷thread_instance_智能指針指向的對象是否爲空,若是爲空則說明進入到這個函數的線程是第一次運行這個函數,那麼就執行17行,從新new一個caffe對象,這個對象是屬於該線程獨有的,存放在該線程的TLS(Thread local storage)中。若是thread_instance_智能指針指向的對象不爲空,說明進入到這個函數的線程已經不是第一次運行到這行代碼了,那麼就直接將本身TLS中的Caffe對象拿來使用就好了。boost::thread_specific_ptr中Get()函數的定義以下圖82行所示:數據結構
這個函數其實就是返回線程私有存儲空間中的對象而已。框架
能夠用下面的示例代碼來驗證boost::thread_specific_ptr的機制:函數
#include <iostream> #include <boost/thread/mutex.hpp> #include <boost/thread/thread.hpp> #include <boost/thread/tss.hpp> 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() { boost::thread thrd1(count(1)); boost::thread thrd2(count(2)); thrd1.join(); thrd2.join(); return 0; }
這段代碼聲明瞭一個指向int類型的智能指針,main函數中使用了兩個線程來訪問該ptr,每一個線程都會對ptr指向的值執行加法操做,從輸出結果能夠看到,兩個線程的值互不干擾:spa
該代碼採用cmake編寫,完整的工程項目點擊這裏。線程