多线程遇上对象析构是个很麻烦的问题,这里我用一个多线程的单例模式去演示一下对象析构的问题
懒汉模式,加锁,线程安全
懒汉模式:需要的时候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<mutex> _lock(_Mutex);//加锁
if (instance == nullptr)
{
instance = new Message();
}
}
return instance;
}
void Message::Del_instance()//删掉对象
{
lock_guard<mutex> _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();//创建工作线程
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<mutex> _lock(_Mutex);//加锁
if (instance == nullptr)
{
instance = new Message();
instance->AddWordThread();
}
}
return instance;
}
void Message::Del_instance()//删掉对象
{
lock_guard<mutex> _lock(_Mutex);//加锁
if (instance != nullptr)
{
delete instance;
instance = nullptr;
}
}
void Message::AddMess(const string& sm)//多线程..添加消息
{
lock_guard<mutex> _lock(this->_m_mutex);//加的是当前对象指向的锁
//a线程输入 b就不要输入了
message = sm;
}
void Message::AddWordThread()//创建线程
{
thread m_th(&Message::WordThread,this);//创建了一个线程
m_th.detach();//线程分离出去
}
void Message::WordThread(Message* pm)//工作线程
{
for (;;)
{
lock_guard<mutex>_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我没有实现同步,只是说明一下当对象析构之后,线程还在运行会有什么问题?
1、对象可能先于线程死亡,WorkThread就会进不去,什么也不执行
每增添一个消息之后让他睡眠个100毫秒看看,工作线程也多睡会让他打印出来我们看看
void Message::WordThread(Message* pm)//工作线程
{
for (;;)
{
lock_guard<mutex>_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();//删除单例对象
}
程序崩溃--->在打印完毕之后,懒汉模式创建的单例对象已经被析构了,但是工作线程里的pm已经没有资源了工作线程就会奔溃
如果要使他正常的话就得让工作线程结束之后,单例对象析构
解决方案:
让判断线程是否结束,如果结束了,线程join,给个bool类型stop用来判断所有线程走完没,走完了,修改析构函数让他为真,把线程对象至为空,当工作线程看到stop为真了,直接退出。
不过这么写针对这个用例来说能走,不过要是再加个funa线程函数,主线程一次走两个,走多个就会出现问题了。
完美解决,引入shared_ptr和weak_ptr:要知道对于c++智能指针在多线程上面发挥巨大作用
还得了解一下,enable_shared_from_this 的使用
有关std::enable_shared_from_this_Oorik
class Message:public enable_shared_from_this<Message>//为了安全获得当前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();//创建工作线程
public:
~Message(){
_stop = true;
pwth->join();
cout << "工作线程结束.." << endl;
pwth = nullptr;
cout << "Message结束.." << endl;
}
private:
//static Message* instance;//实例指针
static shared_ptr<Message>instance;
//多线程下 多个线程,我们要给出互斥量
static mutex _Mutex;
static void WordThread(weak_ptr<Message>pm);//工作线程
public:
//static Message* Get_instance();//获取实例对象
static shared_ptr<Message>Get_instance();
static void Del_instance();//删除实例
void AddMess(const string& sm);//给此单例对象添加消息
void SetStop() { _stop = true; }
};
//Message* Message::instance=nullptr;
shared_ptr<Message>Message::instance(nullptr);
mutex Message::_Mutex;
shared_ptr<Message> Message::Get_instance()//获得对象
{
if (instance == nullptr) //两个if 多重判断 减少一下锁开销
{
lock_guard<mutex> _lock(_Mutex);//加锁
if (instance == nullptr)
{
//instance = new Message();
instance = shared_ptr<Message>(new Message());
instance->AddWordThread();
}
}
return instance;
}
void Message::Del_instance()//删掉对象
{
lock_guard<mutex> _lock(_Mutex);//加锁
if (instance != nullptr)
{
//delete instance;
instance.reset();//当uses=0的时候 释放资源
//nstance = nullptr;
}
}
void Message::AddMess(const string& sm)//多线程..添加消息
{
lock_guard<mutex> _lock(this->_m_mutex);//加的是当前对象指向的锁
//a线程输入 b就不要输入了
message = sm;
}
void Message::AddWordThread()//创建线程
{
//thread m_th(&Message::WordThread,this);//创建了一个线程
//m_th.detach();//线程分离出去
weak_ptr<Message>pa =shared_from_this();//获取this拥有资源的ptr
pwth = new thread(&Message::WordThread, pa);
}
void Message::WordThread(weak_ptr<Message>pm)//工作线程
{
for (;;)
{
shared_ptr<Message>pa = pm.lock();
if (!pa)return;
lock_guard<mutex>_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_ptr<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(1));
//让工作线程跑起来
}
Message::Del_instance();//删除单例对象
}
void funa()
{
shared_ptr<Message> pa = 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;
}
完事收工