当前位置: 首页 > news >正文

c++11新特性-下

c++11的线程库可以跨平台使用。

原子性操作库(atomic)

不需要对原子类型变量进行加锁解锁操作,线程能够对原子类型变量互斥的访问。

atmoic<T> t; // 声明一个类型为T的原子类型变量t

在C++11中,原子类 型只能从其模板参数中进行构造,不允许原子类型进行拷贝构造、移动构造以及operator=

#include <atomic>
int main()
{atomic<int> a1(0);//atomic<int> a2(a1); // 编译失败atomic<int> a2(0);//a2 = a1; // 编译失败return 0;
}

thread的使用

仿函数配合thread使用

//仿函数配合thread使用
atomic<int> x = 0;
struct Add
{void operator()(int n){for (int i = 0; i < n; ++i)++x;}
};
thread t1(Add(), 1000000);

 也可以使用匿名对象。

lambda配合thread使用

atomic<int> x = 0;
auto add = [&x](int n) {for (int i = 0; i < n; ++i)++x;};
thread t1(add, 1000000);
thread t2(add, 1000000);
cout << t1.get_id() << endl;
cout << t2.get_id() << endl;
t1.join();
t2.join();
cout << x << endl;

优化:

atomic<int> x = 0;
int m, n;
cin >> m >> n;
vector<thread> vthreads;
for (int i = 0; i < m; ++i)
{vthreads.push_back(thread([&x](int count) {for (int i = 0; i < count; ++i)++x;}, n));
}
for (auto& t : vthreads)
{cout << t.get_id() << ".join()" << endl;t.join();
}
cout << x << endl;
vector<thread> vthreads(m);
for (int i = 0; i < m; ++i)
{vthreads[i]=thread([&x](int count) {for (int i = 0; i < count; ++i)++x;}, n);
}

让两个线程分别打印奇偶数

int n = 10;
mutex mtx1, mtx2;
condition_variable cv1, cv2;
thread t1([&]() {for (int i = 0; i < n; i += 2){cout << this_thread::get_id() << ":" << i << endl;cv2.notify_one();cv1.wait((unique_lock<mutex>&)unique_lock<mutex>(mtx1));}});
thread t2([&]() {for (int i = 1; i < n; i += 2){cv2.wait((unique_lock<mutex>&)unique_lock<mutex>(mtx2));cout << this_thread::get_id() << ":" << i << endl;cv1.notify_one();}});
t1.join();
t2.join();

throw可以抛出任意类型的对象。

catch(...)可以捕获任意类型的异常,问题是不知道异常错误是什么。

double Division(int a, int b)
{// 当b == 0时抛出异常if (b == 0)throw "Division by zero condition!";else return ((double)a / (double)b);
}void Func()
{int len, time;cin >> len >> time;cout << Division(len, time) << endl;
}
int main()
{try {Func();}catch (const char* errmsg) {cout << errmsg << endl;}catch(...){cout<<"unkown exception"<<endl; }return 0;
}

智能指针

template<class T>
class SmartPtr
{
public:SmartPtr(T* ptr):_ptr(ptr){}~SmartPtr(){if (_ptr){cout << "delete: " << _ptr << endl;delete _ptr;}}
private:T* _ptr;
};

RAII是一种托管资源的方式,智能指针是依靠这种RAII实现的。

C++98  auto_ptr

将管理权转移

缺陷:ap2=ap1时,ap1将悬空,访问就会报错。

auto_ptr<int> ap1(new int);
auto_ptr<int> ap2 = ap1;

C++11 unique_ptr

缺陷:无法应对需要拷贝的场景。

unique_ptr<int> ap1(new int);

C++11 shared_ptr

namespace sp
{template<class T>class shared_ptr{public:shared_ptr(T* ptr):_ptr(ptr),_pcount(new int(1)){}shared_ptr(shared_ptr<T>& sp):_ptr(sp._str), _pcount(new int(1)){++(*_pcount);}~shared_ptr(){if (--(*_pcount)==0&&_ptr){cout << "delete: " << _ptr << endl;delete _ptr;_ptr = nullptr;}}private:T* _ptr;int* _pcount;};
}
//sp1=sp4shared_ptr<T>& operator=(shared_ptr<T>& sp){if (this != &sp){if (--(*_pcount) == 0){delete _pcount;delete _ptr;}_ptr = sp._ptr;_pcount = sp._pcount;++(*_pcount);}return *this;}

引用计数为0时才能对_ptr进行释放,否则会发生内存泄漏。

++操作最终会被翻译为3条汇编指令。

namespace sp
{template<class T>class shared_ptr{public:shared_ptr(T* ptr):_ptr(ptr),_pcount(new int(1)),_pmtx(new mutex){}shared_ptr(shared_ptr<T>& sp):_ptr(sp._ptr), _pcount(sp._pcount),_pmtx(sp._pmtx){//++(*_pcount);add_ref_count();}void add_ref_count(){_pmtx.lock();++(*_pcount);_pmtx.unlock();}void release(){bool flag = true;_pmtx.lock();if (--(*_pcount) == 0 && _ptr){cout << "delete: " << _ptr << endl;delete _ptr;_ptr = nullptr;delete _pcount;_pcount = nullptr;flag = true;}_pmtx.unlock();if (flag == true){delete _pmtx;_ptrx = nullptr;}}//sp1=sp4shared_ptr<T>& operator=(shared_ptr<T>& sp){if (this != &sp){release();_ptr = sp._ptr;_pcount = sp._pcount;++(*_pcount);}return *this;}~shared_ptr(){release();}private:T* _ptr;int* _pcount;mutex _pmtx;};
}

shared_ptr:不能解决循环引用的问题

weak_ptr: 可以辅助shared_ptr解决循环引用的问题,严格来说weak_ptr不是智能指针。

template<class T>
class weak_ptr
{
public:weak_ptr() = default;weak_ptr(const sp::shared_ptr<T>& sp):_ptr(sp.get_ptr()){}weak_ptr<T>& operator=(const shared_ptr<T>& sp){_ptr = sp.get_ptr();return *this;}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}T* get_ptr() const{return _ptr;}
private:T* _ptr;
};
struct ListNode
{int val;sp::shared_ptr<ListNode> _spnext;sp::shared_ptr<ListNode> _spprev;ListNode():val(0), _spnext(nullptr), _spprev(nullptr){}~ListNode(){cout << "~ListNode()" << endl;}
};
sp::shared_ptr<ListNode> spn1(new ListNode);
sp::shared_ptr<ListNode> spn2(new ListNode);
spn1->_spnext = spn2;
spn2->_spprev = spn1;

智能指针是RAII设计思想的体现

本质上RAII就是借助了构造函数和析构函数,构造函数和析构函数的特点都是自动调用。

使用RAII思想设计的锁管理守卫

template<class lock>
class LockGuard
{
public:LockGuard(Lock& lock):_lk(lock){_lk.lock();}~LockGuard(){cout << "解锁" << endl;_lk.unlock();}
private:Lock& _lk;
};

如何实现,创建出的类只能在堆上?

class HeapOnly
{
public:static HeapOnly* GetObj(){return new HeapOnly;}HeapOnly(const HeapOnly&) = delete;
private:HeapOnly(){}};
shared_ptr<HeapOnly> sp1(HeapOnly::GetObj());
shared_ptr<HeapOnly> sp2(HeapOnly::GetObj());

如何实现,创建出的类只能在栈上?

class StackOnly
{
public:static StackOnly GetObj(){return StackOnly();//传值返回需要调用拷贝构造}
private:StackOnly() {}};
StackOnly so = StackOnly::GetObj();
StackOnly* p = new StackOnly;//operator new+ 构造函数

构造函数私有化后,这个类就不能被继承了。

单例模式

简单的单例模式

懒汉模式:

class Singleton
{
public:static Singleton* GetInstance(){//sleep(1000);//_mtx.lock();if(_pinst==nullptr){unique_lock<mutex> lock(_mtx);if (_pinst == nullptr){_pinst = new Singleton;}}//_mtx.unlock();return _pinst;}
private:Singleton() {}Singleton(const Singleton& s) = delete;static Singleton* _pinst;static mutex _mtx;
};
Singleton* Singleton::_pinst = nullptr;
mutex Singleton::_mtx;

第一个if是为了防止对象已经创建好之后2,还需要每次加锁,造成锁的浪费

第二个if是防止非原子操作导致多个线程一起写

饿汉模式

class Singleton
{
public:static Singleton* GetInstance(){return &_inst;}Singleton(const Singleton&) = delete;
private:Singleton(){}static Singleton _inst;
};

总结:

1.懒汉模式需要考虑线程安全和释放的问题,实现复杂而饿汉模式实现简单

2.懒汉模式是懒加载模式需要再初始化创建对象,不会影响程序启动,

饿汉模式程序启动时就创建实例化对象,会导致程序变慢

3.如何有多个单例类,假设有依赖关系(B依赖A)要求A单例先创建初始化,B单例在创建初始化,则不能用饿汉模式,饿汉模式无法保证创建初始化顺序,懒汉模式可以手动控制。


http://www.mrgr.cn/news/40460.html

相关文章:

  • PCL 将点云投影到圆柱(Ransac拟合)
  • 基于NFSR和S盒的国产流密码算法Bagua
  • 快速了解:MySQL InnoDB和MyISAM的区别
  • MATLAB数字水印系统
  • 计算机网络自顶向下(2)----socket编程
  • 【YOLO系列】YOLOv11正式发布!
  • 足球青训俱乐部后台:Spring Boot开发策略
  • SOMEIP_ETS_144: SD_Reserved_Field_Endpoint_Option_set
  • stm32单片机学习 - MDK仿真调试
  • u盘格式化后数据能恢复吗?2024年Top4恢复神器来帮忙
  • 基于JAVA+SpringBoot+Vue的电商平台的设计与实现
  • 第十讲-显示控件QLabel
  • 论文笔记:LAFF 文本到视频检索的新基准
  • 滚雪球学MySQL[2.3讲]:MySQL数据过滤与排序详解:WHERE条件、ORDER BY排序与LIMIT分页查询
  • 「漏洞复现」EDU 某智慧平台 PersonalDayInOutSchoolData SQL注入漏洞
  • TypeScript 算法手册【选择排序】
  • 【Linux学习】基本指令其二
  • Leetcode45. 跳跃游戏 II
  • 关于计算机算法设计方法的思考
  • 监控易监测对象及指标之:Exchange邮件服务器监测