多線程遇上對象析構(gòu)是個很麻煩的問題,這里我用一個多線程的單例模式去演示一下對象析構(gòu)的問題
創(chuàng)新互聯(lián)服務項目包括溫州網(wǎng)站建設、溫州網(wǎng)站制作、溫州網(wǎng)頁制作以及溫州網(wǎng)絡營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術優(yōu)勢、行業(yè)經(jīng)驗、深度合作伙伴關系等,向廣大中小型企業(yè)、政府機構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,溫州網(wǎng)站推廣取得了明顯的社會效益與經(jīng)濟效益。目前,我們服務的客戶以成都為中心已經(jīng)輻射到溫州省份的部分城市,未來相信會繼續(xù)擴大服務區(qū)域并繼續(xù)獲得客戶的支持與信任!懶漢模式,加鎖,線程安全
懶漢模式:需要的時候new一個對象,不需要的時候delete
(線程安全的懶漢)單例模式的基本代碼示例:
class Message {
private:
Message(){}
Message(const Message&) = delete;
Message& operator=(const Message&) = delete;
~Message(){}
private:
static Message* instance;//實例指針
//多線程下 多個線程,我們要給出互斥量
static mutex _Mutex;
public:
static Message* Get_instance();//獲取實例對象
static void Del_instance();//刪除實例
};
Message* instance=nullptr;
mutex Message::_Mutex;
Message* Message::Get_instance()//獲得對象
{
if (instance == nullptr) //兩個if 多重判斷 減少一下鎖開銷
{
lock_guard_lock(_Mutex);//加鎖
if (instance == nullptr)
{
instance = new Message();
}
}
return instance;
}
void Message::Del_instance()//刪掉對象
{
lock_guard_lock(_Mutex);//加鎖
if (instance != nullptr)
{
delete instance;
instance = nullptr;
}
}
加入多線程的一些屬性
代碼如下:
class Message {
private:
string message;//單例對象 a b c線程
mutex _m_mutex;//有競爭 要互斥
Message(){}
Message(const Message&) = delete;
Message& operator=(const Message&) = delete;
~Message(){}
void AddWordThread();//創(chuàng)建工作線程
private:
static Message* instance;//實例指針
//多線程下 多個線程,我們要給出互斥量
static mutex _Mutex;
static void WordThread(Message* pm);//工作線程
public:
static Message* Get_instance();//獲取實例對象
static void Del_instance();//刪除實例
void AddMess(const string& sm);//給此單例對象添加消息
};
Message* Message::instance=nullptr;
mutex Message::_Mutex;
Message* Message::Get_instance()//獲得對象
{
if (instance == nullptr) //兩個if 多重判斷 減少一下鎖開銷
{
lock_guard_lock(_Mutex);//加鎖
if (instance == nullptr)
{
instance = new Message();
instance->AddWordThread();
}
}
return instance;
}
void Message::Del_instance()//刪掉對象
{
lock_guard_lock(_Mutex);//加鎖
if (instance != nullptr)
{
delete instance;
instance = nullptr;
}
}
void Message::AddMess(const string& sm)//多線程..添加消息
{
lock_guard_lock(this->_m_mutex);//加的是當前對象指向的鎖
//a線程輸入 b就不要輸入了
message = sm;
}
void Message::AddWordThread()//創(chuàng)建線程
{
thread m_th(&Message::WordThread,this);//創(chuàng)建了一個線程
m_th.detach();//線程分離出去
}
void Message::WordThread(Message* pm)//工作線程
{
for (;;)
{
lock_guard_lock(pm->_m_mutex);//保護的是消息
cout<< "這是工作線程..."<< endl;
if (!pm->message.empty())
{
cout<< pm->message<< endl;
pm->message.clear();
}
}
}
void fun()
{
Message* pa = Message::Get_instance();//獲得單例對象
string sm[] = { "fun","fun_hello","fun_hhhh" };
for (const auto& x : sm)
{
pa->AddMess(x);//添加消息
//this_thread::sleep_for(chrono::milliseconds(100));
}
Message::Del_instance();//刪除單例對象
}
int main()
{
fun();
return 0;
}
這里的AddMess和WorkThread我沒有實現(xiàn)同步,只是說明一下當對象析構(gòu)之后,線程還在運行會有什么問題?
1、對象可能先于線程死亡,WorkThread就會進不去,什么也不執(zhí)行
每增添一個消息之后讓他睡眠個100毫秒看看,工作線程也多睡會讓他打印出來我們看看
void Message::WordThread(Message* pm)//工作線程
{
for (;;)
{
lock_guard_lock(pm->_m_mutex);//保護的是消息
cout<< "這是工作線程..."<< endl;
if (!pm->message.empty())
{
cout<< pm->message<< endl;
pm->message.clear();
}
this_thread::sleep_for(chrono::milliseconds(300));
}
}
void fun()
{
Message* pa = Message::Get_instance();//獲得單例對象
string sm[] = { "fun","fun_hello","fun_hhhh" };
for (const auto& x : sm)
{
pa->AddMess(x);//添加消息
this_thread::sleep_for(chrono::milliseconds(100));
}
Message::Del_instance();//刪除單例對象
}
程序崩潰--->在打印完畢之后,懶漢模式創(chuàng)建的單例對象已經(jīng)被析構(gòu)了,但是工作線程里的pm已經(jīng)沒有資源了工作線程就會奔潰
????
如果要使他正常的話就得讓工作線程結(jié)束之后,單例對象析構(gòu)
解決方案:
讓判斷線程是否結(jié)束,如果結(jié)束了,線程join,給個bool類型stop用來判斷所有線程走完沒,走完了,修改析構(gòu)函數(shù)讓他為真,把線程對象至為空,當工作線程看到stop為真了,直接退出。
不過這么寫針對這個用例來說能走,不過要是再加個funa線程函數(shù),主線程一次走兩個,走多個就會出現(xiàn)問題了。
完美解決,引入shared_ptr和weak_ptr:要知道對于c++智能指針在多線程上面發(fā)揮巨大作用
還得了解一下,enable_shared_from_this 的使用
有關std::enable_shared_from_this_Oorik
class Message:public enable_shared_from_this//為了安全獲得當前this指針的智能指針
{
private:
string message;//單例對象 a b c線程
mutex _m_mutex;//有競爭 要互斥
bool _stop;
thread* pwth;//指向線程的指針
Message():_stop(false),pwth(nullptr){}
Message(const Message&) = delete;
Message& operator=(const Message&) = delete;
void AddWordThread();//創(chuàng)建工作線程
public:
~Message(){
_stop = true;
pwth->join();
cout<< "工作線程結(jié)束.."<< endl;
pwth = nullptr;
cout<< "Message結(jié)束.."<< endl;
}
private:
//static Message* instance;//實例指針
static shared_ptrinstance;
//多線程下 多個線程,我們要給出互斥量
static mutex _Mutex;
static void WordThread(weak_ptrpm);//工作線程
public:
//static Message* Get_instance();//獲取實例對象
static shared_ptrGet_instance();
static void Del_instance();//刪除實例
void AddMess(const string& sm);//給此單例對象添加消息
void SetStop() { _stop = true; }
};
//Message* Message::instance=nullptr;
shared_ptrMessage::instance(nullptr);
mutex Message::_Mutex;
shared_ptrMessage::Get_instance()//獲得對象
{
if (instance == nullptr) //兩個if 多重判斷 減少一下鎖開銷
{
lock_guard_lock(_Mutex);//加鎖
if (instance == nullptr)
{
//instance = new Message();
instance = shared_ptr(new Message());
instance->AddWordThread();
}
}
return instance;
}
void Message::Del_instance()//刪掉對象
{
lock_guard_lock(_Mutex);//加鎖
if (instance != nullptr)
{
//delete instance;
instance.reset();//當uses=0的時候 釋放資源
//nstance = nullptr;
}
}
void Message::AddMess(const string& sm)//多線程..添加消息
{
lock_guard_lock(this->_m_mutex);//加的是當前對象指向的鎖
//a線程輸入 b就不要輸入了
message = sm;
}
void Message::AddWordThread()//創(chuàng)建線程
{
//thread m_th(&Message::WordThread,this);//創(chuàng)建了一個線程
//m_th.detach();//線程分離出去
weak_ptrpa =shared_from_this();//獲取this擁有資源的ptr
pwth = new thread(&Message::WordThread, pa);
}
void Message::WordThread(weak_ptrpm)//工作線程
{
for (;;)
{
shared_ptrpa = pm.lock();
if (!pa)return;
lock_guard_lock(pa->_m_mutex);//保護的是消息
//cout<< "這是工作線程..."<< endl;
if (pa->_stop)
{
return;
}
if (!pa->message.empty())
{
cout<< pa->message<< endl;
pa->message.clear();
}
//this_thread::sleep_for(chrono::milliseconds(300));
}
}
void fun()
{
shared_ptrpa = Message::Get_instance();//獲得單例對象
string sm[] = { "fun","fun_hello","fun_hhhh" };
for (const auto& x : sm)
{
pa->AddMess(x);//添加消息
this_thread::sleep_for(chrono::milliseconds(1));
//讓工作線程跑起來
}
Message::Del_instance();//刪除單例對象
}
void funa()
{
shared_ptrpa = Message::Get_instance();//獲得單例對象
string sm[] = { "funaa","funa_bb","funa_oo" };
for (const auto& x : sm)
{
pa->AddMess(x);//添加消息
this_thread::sleep_for(chrono::milliseconds(2000));
//讓工作線程跑起來
}
Message::Del_instance();//刪除單例對象
}
int main()
{
thread th(fun);
thread tha(funa);
th.join();
tha.join();
cout<< "main over"<< endl;
return 0;
}
完事收工
你是否還在尋找穩(wěn)定的海外服務器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準確流量調(diào)度確保服務器高可用性,企業(yè)級服務器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧