引言
問題出現在實現項目的一個功能的時候,我需要一個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有興趣的朋友可以去看看其文檔,鏈接在文末。
參考: