問題解決:如何管理線程私有(thread_local)的指針變量

引言

問題出現在實現項目的一個功能的時候,我需要一個thread_local的指針,因爲整個項目已經差不多實現了,但在最後發現了內存泄露的問題。因爲實現的是一個偏向於底層的庫,且內存的使用基本都在掌握之內,所以在項目實現之初爲了效率並沒有使用智能指針,但在後來在這裏出現了內存泄露問題。

原本代碼差不多是這樣:

__thread Co_Rountinue_Env* CurrentThread_CoEnv = nullptr;

這樣在線程結束以後很難去把它釋放掉,所以需要想一個方法做到這樣,且不想大規模改動原有代碼,最終的解決方案是這樣的:

__thread Co_Rountinue_Env* CurrentThread_CoEnv = nullptr;

thread_local std::unique_ptr<Co_Rountinue_Env, decltype(Free_Co_Rountinue_Env)*>
                DeleteThread_CoEnv(CurrentThread_CoEnv, Free_Co_Rountinue_Env);

不必在意變量名,基本思路還是使用智能指針去管理內存,我們來看一個模擬的小demo:

#include <bits/stdc++.h>
#include <unistd.h>
using namespace std;

void Delete_(int* para){
    if(para == nullptr) return;
    cout << "nihao\n";
    delete para;
    return;
}
thread_local int* env = nullptr;

thread_local std::unique_ptr<int, decltype(Delete_)*>
    Env(env, Delete_);

void* Routine(void* para){
    Env.reset();
    env = new int(5);
    Env.reset(env);
    cout << "函數結束\n";
    return 0;
}

int main(){
    pthread_t tid[5];
    for(size_t i = 0; i < 2; i++){
        pthread_create(tid + i, nullptr, Routine, 0);
    }
    for(size_t i = 0; i < 2; i++){
        pthread_join(tid[i], nullptr);
    }
    sleep(1);
    return 0;
}

輸出:

函數結束
nihao
函數結束
nihao

這樣就達到了預期。


在解決問題的過程中還發現了boost庫中也有一個玩意兒可以做到這樣,即boost::thread_specific_ptr,它的作用就是用於每線程存儲,且會在線程結束的時候執行預先設置的回調,就類似於一個特殊的智能指針,我們來看看其如何應用:

#include <bits/stdc++.h>
#include <boost/thread/tss.hpp>
#include <unistd.h>
using namespace std;

void Delete_(int* para){
    if(para == nullptr) return;
    cout << "nihao\n";
    delete para;
    return;
}

boost::thread_specific_ptr<int> env {&Delete_};

void* Routine(void* para){
    if(!env.get()){
        env.reset(new int(5));
    }
    cout << *env << endl;
    cout << "函數結束\n";
    return 0;
}

int main(){
    pthread_t tid[5];
    for(size_t i = 0; i < 2; i++){
        pthread_create(tid + i, nullptr, Routine, 0);
    }
    for(size_t i = 0; i < 2; i++){
        pthread_join(tid[i], nullptr);
    }
    sleep(1);
    return 0;
}

執行以下命令:

g++ XXX.cpp -pthread -lboost_system -lboost_thread
./a.out

我們可以在使用時把thread_specific_ptr當做普通指針來用,因爲其本身的成員函數並不多,相比與智能指針來說可謂一個天上一個地下。除去對於指針值的輸出,我們可以看到其他輸出都是一樣的:

5
函數結束
nihao
5
函數結束
nihao

對thread_specific_ptr有興趣的朋友可以去看看其文檔,鏈接在文末。

參考:

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