![](https://img-blog.csdnimg.cn/20201014180756754.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
c++11并发编程历程
文章平均质量分 80
_李白_
内外兼修,方是正途;外是架构,内是数学。
展开
-
linux下线程的同步:互斥锁、自旋锁、读写锁、原子操作(进程也可用原子操作)
1、多线程中的i++问题我们来看一个经典的多线程i++出现的问题/*================================================================* Copyright (C) 2021 baichao All rights reserved.* * 文件名称:iaddadd.cpp* 创 建 者:baichao* 创建日期:2021年04月01日* 描 述:*====================.原创 2021-04-05 22:31:22 · 755 阅读 · 0 评论 -
c++11并发编程历程(17):初探基于锁的并发简单数据结构
设计基于锁的并发数据结构关键是要确保存取数据时要确保存取数据时要锁住正确的互斥元,并且将锁的时间最小化。只用一个互斥元保护一个数据结构是很困难的,你要保证在互斥锁保护区域之外不会被存取,并且不会发生接口所固有的竞争。但是如果使用独立的互斥元来保护数据结构的独立部分,问题会变得更复杂,可能会产生死锁。...原创 2020-12-03 14:30:37 · 493 阅读 · 2 评论 -
c++11并发编程历程(16):并发设计以及并发设计数据结构的思考
1、并发设计的意义 在最基本的层面,为并发设计数据结构意味着多个线程可以同时使用此数据结构,执行相同或不同的操作,并且每个线程都有数据结构的一致性试图。 不会丢失或破坏数据,维持所有不变量,并且没有不确定的竞争条件,此种数据结构就被称为线程安全的。通常,只有在特定的并发存取下,一种数据类型才是安全的。 实际上,并发设计远远不只是为多个线程提供存取数据结构的并发机会。本质上,互斥元提供的是互斥,一次只允许一个线程获取互斥元的锁。一个互斥元通过明确阻止对它所保护数据进行并发存取来保护数据,这被...原创 2020-11-26 07:28:42 · 309 阅读 · 1 评论 -
c++11:std::atomic<T>::fetch_add、std::atomic<T>::fetch_sub
头文件:<atomic>仅为atomic<Integral>(C++11)与atomic<Floating>(C++20)模板特化的成员:T fetch_add( T arg,std::memory_order order = std::memory_order_seq_cst ) noexcept; T fetch_add( T arg,std::memory_order order = std::memory_order_seq_cst ...原创 2020-11-11 00:00:10 · 2056 阅读 · 0 评论 -
c++11:std::atomic<T>::compare_exchange_weak, std::atomic<T>::compare_exchange_strong
头文件:<atomic>函数声明:boolcompare_exchange_weak(T&expected, T desired, std::memory_ordersuccess, std::memory_order failure)noexcept; 原子地比较*this和expected的值,而若它们逐位相等,则以d...原创 2020-11-10 22:03:59 · 623 阅读 · 0 评论 -
c++11:std::atomic
std::atomic<T>::load定义T load( std::memory_order order = std::memory_order_seq_cst ) const noexcept; c++11起 T load( std::memory_order order = std::memory_order_seq_cst ) const volatile noexcept; 原子地加载,并返回原子变量当前的值,按照order...原创 2020-11-01 23:57:43 · 27699 阅读 · 1 评论 -
c++11:std::atomic_flag
std::atomic_flag 是原子布尔类型,但不同于 std::atomic , std::atomic_flag 不提供加载或存储操作。只提供test_and_set和clear方法。// 用于初始化 std::atomic_flag 以清除(置 false )状态的初始化器。这样就可以通过lock和unlock操作,像往常一样互斥地访问临界区了。头文件 #include原创 2020-11-01 22:13:09 · 2373 阅读 · 0 评论 -
c++11:std::memory_order(c++11 六种内存序)
这造成的原因是编译器和cpu实施了重排指令,导致读写顺序会发生变化,只要不存在依赖,代码中后面的指令可能会被放在前面,从而先执行它。memory fence保证的是可见性的顺序:“假如我看到了a的最新值,那么我一定也得看到b的最新值”。线程2在ready为true的时候会访问a,对线程1来说,如果按照正常的执行顺序,那么a先被初始化,然后在将ready赋为true。这样就保证了线程1和线程2的顺序性,比如线程2在看到flag==true时,能看到线程1 realse之前所有操作。我们先来看两个线程代码。原创 2020-10-28 23:30:10 · 7849 阅读 · 3 评论 -
c++11并发编程历程(15):带有future的函数式编程(functional programming,FP)
1、函数式编程一种编程风格,函数调用的结果仅单纯依赖于该函数的参数而不依赖于任何外部状态,纯函数也不修改任何外部状态,函数的影响完全局限在返回值上c++是一种多范型语言妈耶可以用FP风格编写程序。随着lambda函数、std::bind、自动变量类型推导等的引入,c++11变得更容易实现函数式编程。而future是使得c++中FP风格的并发切实可行的最后一块拼图,一个future可以在线程间来回传递,使得一个线程的计算结果依赖于另一个的结果,而无需任何对共享数据的显式访问。2、FP风格的快速排序原创 2020-10-24 10:07:01 · 363 阅读 · 0 评论 -
std::timed_mutex、std::recursive_timed_mutex
1、std::timed_mutexA timed mutex is a time lockable object that is designed to signal when critical sections of code need exclusive access, just like a regular mutex, but additionally supporting timed try-lock requests.As such, a timed_mutex has two add原创 2020-10-19 22:56:55 · 366 阅读 · 0 评论 -
c++11:std::shared_future
类模板 std::shared_future 提供访问异步操作结果的机制,类似 std::future ,除了允许多个线程等候同一共享状态。不同于仅可移动的 std::future (故只有一个实例能指代任何特定的异步结果),std::shared_future 可复制而且多个 shared_future 对象能指代同一共享状态。若每个线程通过其自身的 shared_future 对象副本访问,则从多个线程访问同一共享状态是安全的。shared_future 可用于同时向多个线程发信,类似 std.原创 2020-10-09 15:05:17 · 482 阅读 · 1 评论 -
c++11并发编程历程(14):future中保存异常信息
#include <iostream>#include <thread>#include <cmath> //sqrtdouble square_root(double x){ if(x<0) { throw std::out_of_range("x<0"); } return sqrt(x);}int main(){ square_root(-1);}运行结果:...原创 2020-10-09 10:57:12 · 550 阅读 · 0 评论 -
c++11:std::packaged_task
template <class T> packaged_task; // undefinedtemplate <class Ret, class... Args> class packaged_task<Ret(Args...)>;A packaged_task wraps a callable element and allows its result to be retrieved asynchronously.It is similar to s.原创 2020-09-27 23:37:41 · 367 阅读 · 0 评论 -
c++11 std::future、std::future_status
目录1、std::future2、std::future_status1、std::futuretemplate <class T> future;template <class R&> future<R&>; // specialization : T is a reference type (R&)template <> future<void>; // speci..原创 2020-09-27 22:47:53 · 637 阅读 · 0 评论 -
c++11:std::promise
// promise example#include <iostream> // std::cout#include <functional> // std::ref#include <thread> // std::thread#include <future> // std::promise, std::futurevoid print_int (std::future<int&...原创 2020-09-27 20:21:14 · 458 阅读 · 0 评论 -
c++11:std::async、std::launch
1、std::asyncunspecified policy (1) template <class Fn, class... Args> future<typename result_of<Fn(Args...)>::type> async (Fn&& fn, Args&&... args); specific policy (2) template <class Fn,原创 2020-09-27 16:02:00 · 1623 阅读 · 0 评论 -
c++11并发编程历程(13)使用条件变量建立一个线程安全的泛型队列
上面的代码我们展示了队列在线程间传递数据,是一个实际开发很常见的场景。做的好的话,同步可以被限制在队列本身,大大减少了同步问题和竞争条件。下面我们来抽象提取一个泛型的线程安全队列。...原创 2020-09-23 21:49:18 · 204 阅读 · 0 评论 -
c++11并发编程历程(12)用条件变量等待条件
1、等待事件当一个线程需要等待另一个线程的特定事件时,轮询或者定期检查当然也不失为一个办法。但是这样很不理想。因为当一个线程等待第二个线程完成任务的过程中,有下面几种一下子就能想到的方案:首先,它可以一直检查共享数据(由互斥元保护)中的标识,并且让第二个线程在任务完成时设置该标识。其次,等待的第一个线程可能拥有别的线程需要的资源。 或者你直接让等待线程释放占有的资源,并休眠一定时间(但是要得到恰当的休眠时间是很难的),然后继续请求资源,如果没有拿到能执行的的全部资源,那就继续这个过程。上面的原创 2020-09-21 23:40:05 · 1561 阅读 · 0 评论 -
c++11 std::condition_variable、condition_variable_any、notify_all、notify_one、wait、wait_for、wait_until
目录1、std::condition_variable2、std::condition_variable::notify_all、std::condition_variable::notify_one3、std::condition_variable::wait、std::condition_variable::wait_for、std::condition_variable::wait_until4、condition_variable_any1、std::condition_vari原创 2020-09-17 23:21:06 · 1684 阅读 · 0 评论 -
c++11 std::recursive_mutex
A recursive mutex is a lockable object, just like mutex, but allows the same thread to acquire multiple levels of ownership over the mutex object.This allows to lock (or try-lock) the mutex object from a thread that is already locking it, acquiring a new原创 2020-09-17 19:17:14 · 9597 阅读 · 1 评论 -
c++11并发编程历程(11)在初始化时保护共享数据、保护更少的更新数据(boost::shared_mutex)、递归锁(std::recursive_mutex)
在锁定在恰当的粒度这篇博文里,博主分享了将共享保护数据锁定在恰当的粒度,但是有时候根本就没有一个合适的粒度级别,因为并非所有的对数据结构的访问都要求同样级别的保护,在这种情况下,使用替代机制来替代普通的std::mutex可能才是恰当的。1、在初始化时保护共享数据假设你有一个构造起来非常昂贵的共享资源,只有当实际需要时你才会使用。所以每个请求资源的操作首先检查它是否已经初始化(构造),如果没有则初始化之。std::shared_ptr<some_resource> resource原创 2020-09-17 19:27:18 · 751 阅读 · 0 评论 -
c++11并发编程历程(10)锁定在恰当的粒度
1原创 2020-09-15 22:38:15 · 455 阅读 · 0 评论 -
c++11 std::once_flag、std::call_once
目录1、std::once_flag2、std::call_once1、std::once_flagFlag argument type for call_onceObject of this type are used as arguments forcall_once.Using the same object on different calls tocall_oncein different threads causes a single execution if ca...原创 2020-09-14 23:50:31 · 1652 阅读 · 1 评论 -
c++11并发编程历程(9)死锁的避免方法
一对线程中的每一个都需要同时锁定两个互斥元来执行一些操作,并且每个线程都拥有了一个互斥元,同时等待另一个。线程都无法继续,因为每个线程都在等待另一个释放其互斥元。这种情景成为死锁(deadlock),它是在需要锁定两个或更多互斥元以执行操作时的最大问题。...原创 2020-09-10 21:08:25 · 739 阅读 · 0 评论 -
c++ hierarchical_mutex
hierarchical_mutex函数,只适合结合std::lock_guard使用,直接使用如果不考虑顺序,可能会出现问题。hierarchical_mutex类实现如下(非c++标准类):#include <mutex>class hierarchical_mutex{ std::mutex internal_mutex; unsigned long const hierarchy_value; unsigned long previous_hier原创 2020-09-08 22:49:04 · 1140 阅读 · 0 评论 -
c++11 std::lock,std::lock_guard,unique_lock
template <class Mutex1, class Mutex2, class... Mutexes>void lock (Mutex1& a, Mutex2& b, Mutexes&... cde);Lock multiple mutexesLocks all the objects passed as arguments, blocking the calling thread if necessary.The function locks t.原创 2020-09-07 18:00:12 · 782 阅读 · 0 评论 -
c++11 std::defer_lock, std::try_to_lock, std::adopt_lock
std::adopt_lockValue used as possible argument to the constructor of unique_lock or lock_guard.unique_lock objects constructed with adopt_lock do not lock the mutex object on construction, assuming instead that it is already locked by the current thread原创 2020-09-07 21:55:50 · 2741 阅读 · 0 评论 -
c++11并发编程历程(8)stack类中固有的竞争和解决方法(互斥锁的保护范围,即颗粒度)
通过用互斥元保护共享数据我们知道了可以使用互斥元来保护共享数据。然后,我么接着来看一下std::stack容器适配器的接口原创 2020-09-03 22:54:04 · 432 阅读 · 0 评论 -
c++11并发编程历程(7) 用互斥元保护共享数据(std::mutex、std::lock_guard)
在c++中,通过构造std::mutex的实例来创建互斥元,调用成员函数lock()来锁定它,调用成员函数unlock()来解锁它。 但是这种直接调用成员函数是博主不推荐的一种做法,这意味着你必须在离开函数的每条路径上都调用unlock(),包括由于异常导致的在内。 作为替代,标准c++库提供了std::lock_guar类模板。实现了互斥元的RAII惯用语法(资源获取就是初始化,构造时锁定所给的...原创 2020-04-17 12:20:28 · 384 阅读 · 0 评论 -
c++11并发编程历程(6)在运行时选择线程的数量
线程的开辟数量如何在运行时决定,看如下例子#include <iostream>#include <thread>#include <vector>#include <algorithm>#include <numeric>#include <functional>template<typename _I...原创 2020-04-15 13:47:42 · 469 阅读 · 0 评论 -
c++11并发编程历程(5)转移线程所有权
一个特定的执行线程如何在线程实例之间移动,那么线程的所有权如何实现转移呢,直接看例子原创 2020-04-14 12:02:57 · 273 阅读 · 0 评论 -
c++11并发编程历程(4)线程函数传参
前面介绍的都是无参函数,接下来分享一下含参的线程函数先看一个简单的例子。了解下一般写法#include <iostream>#include <thread>using namespace std;int f(int num,string name){ cout<<"num:"<<num<<",name:"<&l...原创 2020-04-08 13:56:03 · 256 阅读 · 0 评论 -
c++11并发编程历程(3)异常环境下的等待
在c++11并发编程历程(2)中我分享了在非异常的情况下调用join(),本文来看一下在异常环境下调用join()进行等待话不多说,上代码#include <iostream>#include <thread>using namespace std;struct func{ int &m_i; func(int &i) :m_i(i) ...原创 2020-04-01 13:38:18 · 228 阅读 · 0 评论 -
c++11并发编程历程(2)当新线程访问原线程局部变量时,原线程提前结束
直接看代码#include<iostream>#include <thread>#include <ctime>using namespace std;struct func{ int &m_i; func(int &i) :m_i(i) {} void operator()() { for (int i = 0;...原创 2020-03-24 17:03:56 · 417 阅读 · 1 评论 -
c++11并发编程历程(1)初识c++11的thread
c++11开始引入了多线程,先来认识一个简单的c++11代码,鼻祖级别的HelloWorld#include <iostream>#include <thread>using namespace std;void Hello(){ cout<<"Hello World"<<endl;}int main(){ thread...原创 2020-03-19 15:14:34 · 248 阅读 · 0 评论