14 | 十面埋伏的并发:多线程真的很难吗?
该思维导图由 AI 生成,仅供参考
认识线程和多线程
- 深入了解
- 翻译
- 解释
- 总结
多线程编程是当前技术人员必须面对的重要课题。本文从C++语言的角度出发,介绍了线程和多线程的概念,以及多线程开发的实践。文章强调了多线程编程的挑战和重要性,提出了“读而不写”避免数据竞争的原则,并介绍了C++标准库提供的工具,如call_once()和thread_local,来改善多线程应用。此外,文章还介绍了原子变量的概念和使用方法,以及C++标准库提供的线程类thread和异步任务函数async()的使用。总的来说,本文通过介绍C++中的多线程编程工具和技术,为读者提供了更好地规划多线程任务、减少并发冲突、提高多线程编程效率和安全性的方法。文章还展望了C++20加入的协程技术,为读者展示了未来并发编程的发展方向。
《罗剑锋的 C++ 实战笔记》,新⼈⾸单¥59
全部留言(37)
- 最新
- 精选
- 泡泡龙虽然没有C++的多线程经验,但是记得其他语言的多线程,用IDE打断点调试是一个极难的问题
作者回复: 多线程调试从来都不是个简单的工作,一般都是打日志,里面列出线程号和使用的变量,然后再慢慢分析。
2020-06-07221 - 战斗机二虎🐯nginx的自旋锁实现就是一个非常成功的工程级的自旋锁
作者回复: 对,Nginx的自旋锁代码非常精致,值得学习。
2020-07-0620 - 青鸟飞鱼老师你好,假如一个变量用volatile修饰,是不是就可以不用加锁?
作者回复: 这种想法是非常危险的,一定要特别注意。 volatile只是表示变量易变,与线程没有任何关系。 不加锁应该用atomic变量。
2020-06-07912 - 风清扬async那里隐含的坑可以结合如下代码验证: ``` auto task = [](auto x) { //using namespace std::chrono_literals; this_thread::sleep_for( x * 1ms); cout << "sleep for " << x << endl; return x; }; //先输出Hello,world auto f = std::async(task, 100); cout << "Hello,world" << endl; #if 0 //先输出sleep for 100 std::async(task, 100); cout << "Hello,world" << endl; #endif return 0; ```
作者回复: 很好的例子,赞。
2020-11-086 - 范闲C++内怎么做异步呢? 1. Callback 2.多线程+Callback 但是这两个都有个问题,callback也是会阻塞的。如果有A B C D四个流程,B C D分别依赖于前一个的输出,这种callback就会调用栈太深,容易爆栈。 最近对异步编程模式产生了些疑问,应该怎么解决?
作者回复: callback并不能实现异步,但异步多用callback来实现解耦回调,比如actor和proactor这两种异步模式。 我理解的阻塞有两种,一种是io阻塞,一种是cpu计算量阻塞,前者可以用异步回调来避免,而后者就只能用多线程了。 目前在C++里,异步编程主要还是用多线程,而callback难于使用和理解,把处理流程分割的支离破碎,以后可能会用协程更好。
2020-07-315 - 二杠一老师,在多个线程里同时往输出流输出,怎么保证一个线程的单次输出操作是完整的 ? 比如"std::cout << x << std::endl;"怎么保证不会漏掉"std::endl"这个输出,只能加锁吗?
作者回复: 在C++11/14里好像只能这样,在C++20里好像多了一个新的cout对象,是线程安全的。 不过我不太建议在多线程里用cout,一是不安全,二是也没什么意义,改成写日志文件的方式可能会更好。
2020-06-1135 - robonix(比如内部使用线程池或者其他机制)。那么async怎么跟线程池结合呢?老师有没有一些好的参考资料提供哈
作者回复: async内部可能有优化,注意,只是可能,要看编译器具体怎么做,也可能不会优化,而且我们也无法控制他。 想要用线程池,还是得自己写,不过其实也比较简单,创建多个线程用list容纳就可以了。 可以参考boost.thread_pool,它就是这么做的。
2020-06-154 - 被讨厌的勇气当需要获取线程的结果时,使用async可以直接获取其结果;使用thread则需要通过共享数据来获取,需要使用锁、条件变量。 async的缺点是只能获取一次。若需要保证线程一直运行,多次获取其‘结果’时,只能使用thread + condition_variable,不知道这样理解对不对? thread_local的应用场景问题。若不需要共享数据,直接在lambad表达式中的捕获列表中进行值捕获不就每个线程一个副本了,没想出来必须使用thread_local的应用场景。
作者回复: 1.基本正确,async()是一种相当简化的线程用法,目的就是获取future值,如果不是这个场景就不如thread灵活。 2.比如说线程里要保存一些cache数据,很显然这些cache不会是多线程共享的,用thread_local就比较好。可以把它理解成是专门给线程准备的static全局变量。
2020-06-0624 - Stephen子线程会立即脱离主线程的控制流程,单独运行,但共享主线程的数据。这里指的是全局变量吧,像局部变量应该不行吧?
作者回复: 也不一定,看传给子线程什么参数了,局部变量也可以给子线程共享。
2020-06-0653 - dog_brother老师,我们生产环境是c++ 11,但是我们几乎不使用std的thread,主要是pthread系列函数。听说是因为std thread的坑比较多。
作者回复: 这个还是看怎么用吧,仔细看它的api,真正有哪些坑只有自己实际使用了才能知道,也许不会遇到那些坑。 thread使用起来很方便,其实就是对操作系统线程接口的封装,可以先小范围使用,再逐步替换pthread。
2021-04-242