caffe可重入單例機制分析

一個函數可重入是指該函數能夠被多個線程同時調用。大多數函數都不是可重如的,由於不少函數會修改靜態數據結構裏的內容,若是多個線程同時調用,勢必破壞共享的靜態結構。能夠在不改變公共接口的狀況下,將一個非重入函數修改成可重入函數。思想是使用線程的本地存儲來實現,而boost::thread_specific_ptr正好提供了使用TLS(thread local storage)的機制。ios

在caffe框架中,class Caffe是一個單例類,這個類是能夠重入的,便可以被多個線程同時使用:git

image

進入到上圖109行的Get()函數:github

image

這個函數是一個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行所示:數據結構

image

這個函數其實就是返回線程私有存儲空間中的對象而已。框架

能夠用下面的示例代碼來驗證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

image

該代碼採用cmake編寫,完整的工程項目點擊這裏線程

相關文章
相關標籤/搜索