扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
多线程遇上对象析构是个很麻烦的问题,这里我用一个多线程的单例模式去演示一下对象析构的问题
创新互联服务项目包括温州网站建设、温州网站制作、温州网页制作以及温州网络营销策划等。多年来,我们专注于互联网行业,利用自身积累的技术优势、行业经验、深度合作伙伴关系等,向广大中小型企业、政府机构等提供互联网行业的解决方案,温州网站推广取得了明显的社会效益与经济效益。目前,我们服务的客户以成都为中心已经辐射到温州省份的部分城市,未来相信会继续扩大服务区域并继续获得客户的支持与信任!懒汉模式,加锁,线程安全
懒汉模式:需要的时候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();//创建工作线程
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()//创建线程
{
thread m_th(&Message::WordThread,this);//创建了一个线程
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我没有实现同步,只是说明一下当对象析构之后,线程还在运行会有什么问题?
1、对象可能先于线程死亡,WorkThread就会进不去,什么也不执行
每增添一个消息之后让他睡眠个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();//删除单例对象
}
程序崩溃--->在打印完毕之后,懒汉模式创建的单例对象已经被析构了,但是工作线程里的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//为了安全获得当前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_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()//创建线程
{
//thread m_th(&Message::WordThread,this);//创建了一个线程
//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;
}
完事收工
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流