设为首页 加入收藏

TOP

现代C++学习指南-标准库(二)
2023-07-23 13:27:37 】 浏览:60
Tags:现代 习指南
tr。

unique_ptr的对应关系是一对一,无论哪个时刻,只能有一个管理者拥有指针,也就只能由它负责释放了。假如想转移这种对应关系,只能通过std::move操作,不过这个操作之后,原先对象的指针就失效了,它也不再负责管理,所有的任务移交给了新的对象。这种特性特别适合资源敏感型的应用。

线程库

除了内存,线程是开发中另一个重要的课题。线程的难点在于不仅要管理线程对象,还要管理线程对象管理的资源,并且保证线程间数据同步。当然标准库已经做得足够好了,我们需要理解的是使用场景的问题。线程库主要包括线程对象thread,条件对象condition_variable,锁对象mutex
使用thread可以很方便地把程序写成多线程,只需要三步:

void plus(int a,int b){ //第一步:定义线程中要运行的函数
    std::cout<<"running at sub thread"<<std::endl;
    std::cout<<"a + b = "<<a+b<<std::endl;
}

int main(){
    std::thread thread{plus,1,1}; //第二步,定义std::thread对象,将函数作为参数
    std::cout<<"continue running at main thread"<<std::endl;
    thread.join(); //第三步调用线程对象的join函数或者detach函数
    std::cout<<"sub thread finished!"<<std::endl;
}
//输出
//	continue running at main thread
//	running at sub thread
// 	a + b = 2
// 	sub thread finished!

难点在线程间通信,也就是解决两个问题

  1. 线程1更新了变量v的值
  2. 线程2马上能读取到正确的变量v的值,即线程1更新的那个最新值

为了协调这两个过程,就出现了锁对象mutex和条件对象condition_variable。锁对象mutex保证变量按照正确的顺序更改。条件对象condition_variable保证更改能被其他线程监听到。

int a,b;
bool ready = false;
std::mutex mux;
std::condition_variable con;

void plus() {
    std::cout << "running at sub thread" << std::endl;
    //因为我们要读取ready的最新值,所以要用锁保证读取结果的有效性
    std::unique_lock<std::mutex> guard{ mux };
    if (!ready) {
        //数据没准备好,休息一下!
        con.wait(guard); 
    }
    //这里就可以正确读变量a,b了
    std::cout << "a + b =" << a + b << std::endl;
}

int main() {
    std::thread thread{ plus};
    std::cout << "continue running at main thread" << std::endl;
    std::cout << "input a = ";
    std::cin >> a;
    std::cout << "input b = ";
    std::cin >> b;
    {
        //数据准备好了,该通知子线程干活了,用大括号是因为想让锁因为guard的销毁即使释放,从未保证plus里面能重新获得锁
        std::unique_lock<std::mutex> guard{ mux };
        //更新数据
        ready = true;
        //通知
        con.notify_all();
    }
    thread.join();
    std::cout << "sub thread finished!" << std::endl;
}

多线程另一个需要注意的问题就是死锁。死锁的前提是有两个锁

  1. 线程1得到了锁a,还想得锁b
  2. 线程2得到了锁b,还想得锁a

然后,再加上一个前提:某一时刻,只有一个线程能拥有某个锁,就不难得出以下结论:线程a,b除非某一个放弃已得的锁,不然两个线程都会因为没得到需要的锁而一直死等,形成死锁。同时解决死锁的思路也呼之欲出:既然一个得了a,一个得了b,而锁同一时间只能被一个线程得到,那么所有线程都按先得a,再得b的顺序来就不会有锁被占用的问题了。另一个思路则可以从放弃上入手,既然都得不到,那么接下来的任务也做不了,不如直接放弃已经得到的,所以可以考虑使用timed_mutex

其他

还有很多常用的库,如字符串string,时间chrono,还有在定义函数变量时常用的functional,异常exception,更多的内容可以在cplusplus找的参考。

总结

总的来说,标准库提供了一个展现C++语言能力的平台:帮助开发者更好更快完成开发任务的同时,还能启迪开发者实现更好的抽象和实践。如我就从标准库中学到了更规范地定义函数参数,更好的封装,以及其他好的思路。学习标准库不仅更好地掌握了语言本身,还掌握了更全面地分析问题,解决问题的方法,是值得花费一段时间学习的。
容器类是几乎所有项目都会用到的,也是比较好掌握的,主要可以从数据结构方面对照学习;智能指针则是处理指针问题的好帮手;线程相关的库是比较难掌握的,关键是要想明白使用场景和极端情况下的边界问题。很多时候边界问题可能不那么直观。如线程要求获得锁的情况就分为:锁空闲,锁被其他线程占有,锁被自己占有。不同的边界对于不同的锁,预期结果也是不同的,只有在明确场景的情况下,才能更好地理清锁的关系,从而解决好问题。
最好的学习还是在实践中主动使用。对于我,通常在遇到新问题的时候会先查查标准库有没有相应的库,有的话就是学习这个库的好时机。可以先概览库的定义和解决的问题,然后分析它提供的类,函数,对象等,再将自己的理解转换为项目中的代码,最后在实际效果中检验和修正想法,完成库的学习。

首页 上一页 1 2 下一页 尾页 2/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇C++面试八股文:std::string是如.. 下一篇【QCustomPlot】使用方法(动态库..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目