![](https://img-blog.csdnimg.cn/20190927151026427.png?x-oss-process=image/resize,m_fixed,h_224,w_224)
cpp多线程精进
文章平均质量分 74
cpp多线程精进
infralan
Major in:linux内核 虚拟化 云原生,熟悉:分布式、网络、存储,感兴趣:计算、数据库、机器学习系统。
展开
-
时间与并发
并发的本质是时间问题。同步就是force一个时间上的操作顺序。临界区相当于用锁实现的原子性操作。在分布式系统上,Total order是可能顺序世界的一个实例,partial order是加入因果关系后的限制。可见点、生效点、强制点、barrier都是为了规整并发操作的时间顺序。规整性的程度就是区别。通信原语、同步原语本质上是将两个局部的子系统里的时间参考系纳入到上层的时间参考系中。多核CPU是一个分布式系统,内存模型就是一个例子。事务也算是一个并发系统。隔离性的体现。由于跟时间有关,并发的Bu原创 2021-07-09 21:29:10 · 155 阅读 · 0 评论 -
语言的并发设施
实现并行程序的主要方法有多线程&锁等。其中多线程&锁效率高,但是TM的不好写啊!!!我们直观的讲讲为什么难写。我们一般写程序时,我们只需要关注我正在写的函数就行,也就是说我只需要关心局部信息。并且在调用函数时,我不需要知道被调用函数的实现细节,这是抽象。我们处理复杂任务时希望处理方法能够满足这两个条件:局部&抽象。但是锁机制破坏了这两个条件:”出于多种原因,可变状态和锁容易出问题。锁意味着要整理代码中的依赖性,使开发人员对于执行路径和预期结果有理可循。但是,由于锁的多个方面未加以实原创 2021-06-25 16:15:12 · 43 阅读 · 0 评论 -
锁无法解决异步信号安全
锁无法解决异步信号安全与线程安全类似的概念就是异步信号安全。异步信号安全操作可保证不会干扰正被中断的操作。当信号处理程序操作干扰正被中断的操作时,就会引发异步信号安全问题。例如,假设程序正在调用 printf(3S),且其调用程序调用 printf() 时出现了信号。在这种情况下,两个 printf() 语句的输出彼此关联。要避免关联输出,当 printf() 可能被信号中断时,处理程序不应直接调用 printf()。无法使用同步元语来解决此问题。 在信号处理程序与正被同步的操作之间执行的任何同步尝原创 2021-07-08 19:49:18 · 119 阅读 · 0 评论 -
异步信号安全
异步信号安全Linux 中可重入这个概念一般只有在 signal 的场景下有意义,叫 async-signal-safe。很多线程安全的函数都是不可重入的,例如 malloc。可重入的函数一般也是线程安全的,虽然据说有反例,但我没见过。异步可重入跟线程安全不是一回事,虽然有时候两者同时满足。Posix中大多数函数都是线程安全的,但只有少数是 async-signal-safe。线程安全函数能够使不同的线程访问同一块地址空间,而可重入函数要求不同的执行流对数据的操作互不影响使结果是相同的。在Unix原创 2021-07-08 18:41:16 · 686 阅读 · 0 评论 -
可重入和线程安全wiki
可重入和线程安全wiki可重入代码(Reentrant Code)又称为 “纯代码” (Pure Code),是一种允许多个进程同时访问的代码。为使各个进程所执行的代码完全相同,绝对不允许可重入代码在执行中有任何改变。因此,可重入代码是一种不允许任何进程对它进行修改的代码。但事实上,大多数代码在执行时都可能有些改变,例如,用于控制程序执行次数的变量以及指针、信号量及数组等。为此,在每个进程中,都必须配以局部数据区,把在执行中可能改变的部分拷贝到该数据区,这样,程序在执行时,只需对该数据区(属于该进程私有)原创 2021-07-08 18:12:46 · 1307 阅读 · 1 评论 -
条件变量的正确使用
条件变量的正确使用陈硕 https://www.cnblogs.com/Solstice/p/3309089.htmlTL;DR 如果你能一眼看出 https://gist.github.com/chenshuo/6430925 中的那 8 个 Waiter classes 哪些是对的哪些是错的,本文就不必看了。我质疑某本书对 Pthreads 条件变量的封装是错的,因为它没有把 mutex 的 lock()/unlock() 函数暴露出来,导致无法实用。后来大家讨论的分歧是这个 cond class原创 2021-07-07 20:29:36 · 389 阅读 · 0 评论 -
条件变量的陷阱与思考
条件变量的陷阱与思考前言在多线程编程中,互斥锁与条件变量恐怕是最常用也是最实用的线程同步原语。关于条件变量一共也就pthread_cond_init、pthread_cond_destroy、pthread_cond_wait、pthread_cond_timedwait、pthread_cond_signal、pthread_cond_broadcast这么几个函数,但是在实际使用中却是很容易用错,后文将来分析几种常见使用情况的正确性。分析下面是一个辅助基类、便于减少篇幅(为了简单起见,后文中的原创 2021-07-07 20:18:45 · 117 阅读 · 2 评论 -
永远不要用volatile保证多线程安全
永远不要用volatile保证多线程安全C/C++多线程编程中不要使用volatile。(注:这里的意思指的是指望volatile解决多线程竞争问题是有很大风险的,除非所用的环境系统不可靠才会为了保险加上volatile,或者是从极限效率考虑来实现很底层的接口。这要求编写者对程序逻辑走向很清楚才行,不然就会出错)C++11标准中明确指出解决多线程的数据竞争问题应该使用原子操作或者互斥锁。C和C++中的volatile并不是用来解决多线程竞争问题的,而是用来修饰一些因为程序不可控因素导致变化的变量,比如原创 2021-07-07 17:54:42 · 1419 阅读 · 0 评论 -
atomic编程demo
atomic编程demo前言多线程并发读写在编写多线程程序时,最重要的问题就是多线程间共享数据的保护。多个线程之间共享地址空间,所以多个线程共享进程中的全局变量和堆,都可以对全局变量和堆上的数据进行读写,但是如果两个线程同时修改同一个数据,可能造成某线程的修改丢失;如果一个线程写的同时,另一个线程去读该数据时可能会读到写了一半的数据。这些行为都是线程不安全的行为,会造成程序运行逻辑出现错误。举个最简单的例子:#include <iostream>#include <thread&原创 2021-07-07 17:28:03 · 154 阅读 · 0 评论 -
如何测试单例模式demo
如何测试单例模式什么是线程安全?在拥有共享数据的多条线程并行执行的程序中,线程安全的代码会通过同步机制保证各个线程都可以正常且正确的执行,不会出现数据污染等意外情况。如何保证线程安全?给共享的资源加把锁,保证每个资源变量每时每刻至多被一个线程占用。让线程也拥有资源,不用去共享进程中的资源。如: 使用threadlocal可以为每个线程的维护一个私有的本地变量。什么是单例模式?单例模式指在整个系统生命周期里,保证一个类只能产生一个实例,确保该类的唯一性。单例模式分类单例模式可以分为懒原创 2021-07-07 16:33:05 · 257 阅读 · 0 评论 -
标准库对操作系统的线程封装
标准库对操作系统的线程封装利用c++操作多线程和直接利用linux系统调用多线程有什么区别?c++接口的功能更少这些都属于系统调用,只是封装不同。你用linux c,线程你会用到pthread库你用linux c++,在pthread库上封装了C++类型的API,封装上比pthread易用,除了创建还有mutex_lock、condition都有封装#include <stdint.h>#include <thread>int thread_test(const ch原创 2021-07-07 13:47:10 · 112 阅读 · 0 评论 -
cpp无锁编程demo
C++11无锁编程demohttps://zhuanlan.zhihu.com/p/24983412不讲语言特性,只从工程角度出发,个人觉得C++标准委员会在C++11中对多线程库的引入是有史以来做得最人道的一件事;今天我将就C++11多线程中的atomic原子操作展开讨论;比较互斥锁,自旋锁(spinlock),无锁编程的异同,并进行性能测试;最后会讨论一下内存序的问题;为了流畅阅读你最好先熟悉一下C++11 Atomic的基本操作英文文档,这里还有一份我觉得做得很用心的关于C++11并发编程的中文教原创 2021-07-07 13:36:17 · 225 阅读 · 0 评论 -
cppref 内存模型
cppref 内存模型此篇讨论一下 C++ 当中的内存模型。文中内容基本上是 CPP reference 上对应页面的翻译,有删减和补充。https://en.cppreference.com/w/cpp/language/memory_model内存模型为 C++ 抽象机器定义了计算机内存存储语义。C++ 程序可用的内存是一个或多个连续的字节序列。每个字节有自己独有的内存地址。字节(Byte)字节是内存中的最小可寻址单元,由连续的多个比特组成。C++ 中,char/unsigned char/原创 2021-07-06 23:15:17 · 436 阅读 · 2 评论 -
cppref memory_order翻译
cppref memory_modelhttps://en.cppreference.com/w/cpp/language/memory_model文中内容基本上是 CPP reference 上对应页面术语部分的翻译,有删减和补充。线程间同步及内存顺序决定表达式的求值(evaluations)及其副作用(side effects)在不同线程中的顺序。首先有相关术语的定义。消费操作(consume operation)配置了 std::memory_order_consume原创 2021-07-06 22:43:45 · 233 阅读 · 0 评论 -
保护线程间的共享数据
程序员的自我修养(六):保护线程间的共享数据多进程和多线程最本质的区别在于共享和隔离的程度不同。对于多进程方式来说,因为隔离程度高,所以程序员很少需要去担心进程空间的数据被破坏;但是并发任务之间共享数据就变得很困难了。对于多线程方式来说,因为隔离程度低,所以共享数据非常容易;但是,相应地,程序员需要更多地考虑如何在线程之间安全地共享数据。这就引出了所谓的「线程安全」问题。此篇,我们讨论如何在线程之间安全地共享数据。在线程间共享数据的问题引子让我们先来看一个有味道的例子。假设你邀请朋友到家里来派对原创 2021-07-06 22:01:31 · 394 阅读 · 0 评论 -
云风 极不和谐的 fork 多线程程序
极不和谐的 fork 多线程程序继续前几天的话题。做梦幻西游服务器优化的事情。以往的代码,定期存盘的工作分两个步骤,把 VM 里的动态数据序列化,然后把序列化后的数据写盘。这两个步骤,序列化工作并没有独立在单独线程/进程里做,而是放在主线程的。IO 部分则在一个独立进程中。序列化任务是个繁琐的过程。非常耗时(相对于 MMORPG 这个需要对用户请求快速反应的环境)。当玩家同时在线人数升高时,一个简便的优化方法是把整个序列化任务分步完成,分摊到多个心跳内。这里虽然有一些数据一致性问题,但也有不同的手段解决原创 2021-07-06 21:43:41 · 89 阅读 · 0 评论 -
linux进程高级属性之安全的fork
linux进程高级属性之安全的fork安全性问题:当线程调用fork函数时,就为子进程创建了整个进程地址空间的副本,子进程通过继承整个地址空间的副本,也会将父进程的互斥量、读写锁、条件变量的状态继承过来。也就是说,如果父进程中互斥量是锁着的,那么在子进程中互斥量也是锁着的(尽管子进程自己还没有来得及lock),这是非常不安全的,因为子进程中拥有锁的线程也许已经消失,只会保留fork的那个线程。解决办法: int pthread_atfork(void (*prepare)(void), void (原创 2021-07-06 21:04:40 · 128 阅读 · 0 评论 -
fork安全()
fork安全()转载 https://liam.page/2017/01/17/fork-safe/ 有所补充本文将探讨一个与多进程、多线程相关的问题:fork()-安全。抛出异常首先我们来看这样的代码//mutex_deadlock.cpp//g++ mutex_deadlock.cpp -lpthread#include <pthread.h>#include <time.h>#include <unistd.h>using namespace原创 2021-07-06 19:34:52 · 301 阅读 · 1 评论 -
谨慎使用多线程中的fork
谨慎使用多线程中的fork在单核时代,大家所编写的程序都是单进程/单线程程序。随着计算机硬件技术的发展,进入了多核时代后,为了降低响应时间,重复充分利用多核cpu的资源,使用多进程编程的手段逐渐被人们接受和掌握。然而因为创建一个进程代价比较大,多线程编程的手段也就逐渐被人们认可和喜爱了。记得在我刚刚学习线程进程的时候就想,为什么很少见人把多进程和多线程结合起来使用呢,把二者结合起来不是更好吗?现在想想当初真是too young too simple,后文就主要讨论一下这个问题。进程与线程模型进程的经原创 2021-07-06 17:22:38 · 523 阅读 · 0 评论 -
条件变量精髓
条件变量精髓我其实从来没有真正理解这些概念,只是在鹦鹉学舌,因为我从来没去想过,不这样会怎样,也从来没有自己设计过。条件变量其实是多线程reason的极好模范。理解条件变量的枢纽是死锁。对,这两个概念似乎完全不关联,但却是真正紧密扣在一起的。其次的辅助概念就是只触发一次的信号改变通知。这个的意思就是某个线程发出了signal,不管是唤醒一个还是唤醒等待队列上的所有线程,这个唤醒总是只会发出一次,一但没有接收到,就不再次唤醒。也许看上去这个事实很平凡,但却是困扰我的根本。以等待条件变量的线程为例,首原创 2021-07-06 11:09:44 · 53 阅读 · 0 评论 -
cpp多线程编程demo4
程序员的自我修养(五):C++ 多线程编程初步2017 年 05 月 16 日 2020 年 02 月 04 日 Algorithm and Computer Science 248878.2k 15 分钟这是系列文章的第五篇。这篇文章里,我们介绍如何使用 C++ 11 的标准库,进行多线程编程。Babystep好吧,不管学什么编程语言,「Hello world!」总是不会少的。虽然在 C++ 中进行多线程编程依然是在使用 C++,但是迈出 babystep 总是很重要的。让我们从 He原创 2021-07-03 15:41:21 · 226 阅读 · 0 评论 -
cpp多线程编程demo3
cpp多线程编程demo3future promisestd::future对象可以和async,std::packaged_task,std::promise一起使用。这篇文章集中讨论std::future和std::promise。我们经常会遇到需要得到线程返回结果的情况,现在的问题是我们如何实现。举个例子:假设在程序中,我们创建了一个压缩给定文件夹的线程,并且我们希望该线程能够返回新的zip文件的名称和大小。有两种实现方式:1、老方法:使用指针在线程间共享数据传递一个指针到新的线程中,原创 2021-07-03 15:28:02 · 204 阅读 · 3 评论 -
cpp多线程编程demo2
cpp多线程编程demo2数据共享和竞争在多线程环境中,线程间的数据共享很简单,但是在程序中这种简单的数据共享可能会引起问题,其中一种便是竞争条件。什么是竞争条件?竞争条件是发生在多线程应用程序中的一种bug当两个或多个线程并行执行一组操作,访问相同的内存位置,此时,它们中的一个或多个线程会修改内存位置中的数据,这可能会导致一些意外的结果,这就是竞争条件。竞争条件通常较难发现并重现,因为它们并不总是出现,只有当两个或多个线程执行操作的相对顺序导致意外结果时,它们才会发生,通过例子理解:创建原创 2021-07-03 15:10:56 · 195 阅读 · 0 评论 -
cpp多线程编程demo1
cpp多线程编程demo1原作者 https://blog.csdn.net/lijinqi1987/category_5784833.html创建线程c++11线程库原始的c++标准仅支持单线程编程,新的c++标准(c++11或c++0x)于2011年发布,引入了新的线程库。编译器要求Linux: gcc 4.8.1 (完全并发支持)Windows: Visual Studio 2012 and MingW在linux下的编译方法:g++ -std=c++11 sample.cp原创 2021-07-03 14:48:00 · 394 阅读 · 2 评论 -
C++并发编程(C++11到C++17)转载
C++并发编程(C++11到C++17)转载作者:paulqueihttps://paul.pub/cpp-concurrency/为什么要并发编程大型的软件项目常常包含非常多的任务需要处理。例如:对于大量数据的数据流处理,或者是包含复杂GUI界面的应用程序。如果将所有的任务都以串行的方式执行,则整个系统的效率将会非常低下,应用程序的用户体验会非常的差。另一方面,自上个世纪六七十年代英特尔创始人之一 Gordon Moore 提出 摩尔定律 以来,CPU频率以每18个月翻一番的指数速度增长。但这一原创 2021-07-03 14:04:56 · 308 阅读 · 0 评论 -
各种顺序名词含义
各种顺序名词含义1,背景ART虚拟机中(安卓run time)使用futex/atomic实现了自己的Mutex/Condition类(art/runtime/base/mutex.h/mutex.cc),其中使用了AtomicInteger(std::atomic)的封装。要想了解Mutex类的实现原理是,需要搞清楚什么是c++ memory order。弄懂c++ memory order也是必须的。2,什么是memory orderMemory order我认为是目前计算机编程里面比较晦涩难懂原创 2021-07-03 10:55:47 · 375 阅读 · 0 评论 -
cpp内存顺序(二)
cpp内存顺序简单的理解这个问题, 看下面的描述即可.深入理解这个问题, 建议阅读 https://zhuanlan.zhihu.com/p/35668651 后文给出的参考文献.单纯地看一两本书其实很难做到自洽的理解.memory order提供了两种作用:原子操作: 简单的就是cas, 计数器. 原子操作需要处理器支持, 比如cmpxchg, lr/sc.同步语义: 写的前置写对读的后置读可见.同一个处理器访问同一个memory location, 存在data dependency原创 2021-07-07 16:59:49 · 144 阅读 · 0 评论 -
cpp内存顺序(一)
理解了 c++ concurrency in action 5.3.4 小节的内容:Release sequences and synchronizes-with后,对C++ consistency model本质的理解非常有好处.另外读过lamport 的经典论文Time, Clocks, and the Ordering of Events in a Distributed System对理解 C++ memory order 也很有好处.JAVA 与C++ 的内存模型同根同源,都出自与DRF0.原创 2021-07-03 10:53:25 · 177 阅读 · 0 评论 -
当析构函数遇到多线程 转载
当析构函数遇到多线程陈硕https://www.cnblogs.com/Solstice/archive/2010/02/10/dtor_meets_threads.html摘要编写线程安全的类不是难事,用同步原语保护内部状态即可。但是对象的生与死不能由对象自身拥有的互斥器来保护。如何保证即将析构对象 x 的时候,不会有另一个线程正在调用 x 的成员函数?或者说,如何保证在执行 x 的成员函数期间,对象 x 不会在另一个线程被析构?如何避免这种竞态条件是 C++ 多线程编程面临的基本问题,可以借助原创 2021-07-02 20:20:08 · 2617 阅读 · 2 评论 -
为什么多线程读写 shared_ptr 要加锁 转载
为什么多线程读写 shared_ptr 要加锁?陈硕(giantchen_AT_gmail_DOT_com)2012-01-28我在《Linux 多线程服务端编程:使用 muduo C++ 网络库》第 1.9 节“再论 shared_ptr 的线程安全”中写道:(shared_ptr)的引用计数本身是安全且无锁的,但对象的读写则不是,因为 shared_ptr 有两个数据成员,读写操作不能原子化。根据文档(http://www.boost.org/doc/libs/release/libs/smar原创 2021-07-02 19:08:05 · 332 阅读 · 0 评论 -
synchronize-with
只有真正理解这个概念,才能理解多线程的核心。单个线程的重排可以通过原子操作搞定,但多个线程之间的原子操作没有内在的关系,相当于是两个自治的操作序列,或者说两个局部时间域。如何将这两个时间的某些操作强行规定一个先后关系,而其他操作不管,就是synchronize-with所意味的。那么如何做同步呢?就是引入一个点,可以成为同步点,这个点是两个线程的参照物,一个线程的一些操作必须在这个点之前完成,另一个线程的操作必须在这个点之后完成。在代码中就是某个操作成为这个同步点,如何让它成为同步点?就是tagged,原创 2021-07-02 20:43:31 · 543 阅读 · 0 评论