原子操作

C++多线程——原子操作atomic

半世苍凉 提交于 2020-01-11 22:36:37
1. 原子操作 1.1 示例 原子操作 是个不可分割的操作。 在系统的所有线程中,你是不可能观察到原子操作完成了一半这种情况的; 它要么就是做了,要么就是没做,只有这两种可能。 不使用原子操作: # include <iostream> # include <thread> # include <atomic> using namespace std ; long num = 0 ; void addnum ( ) { for ( int i = 0 ; i < 100000 ; i ++ ) num ++ ; //不对全局变量进行互斥访问 } int main ( ) { int nthreads = 2 ; thread t [ nthreads ] ; for ( int i = 0 ; i < nthreads ; i ++ ) t [ i ] = thread ( addnum ) ; for ( auto & th : t ) th . join ( ) ; cout << num << endl ; return 0 ; } 输出结果: 最终结果为 109515 ,这个结果小于 200000 ,说明在对全局变量进行写的时候出现了下面的情况: 明明加了两次,但是因为访问不是互斥的,从而导致实际的值小。 使用原子操作可以避免这种情况的发生

java并发-原子性

走远了吗. 提交于 2020-01-10 19:30:41
原子性就是指该操作是不可再分的。 java.util.concurrent.atomic中有一组使用无锁算法实现的原子操作类。AtomicInteger、AtomicBoolean、AtomicLong 外还有 AtomicReference 。它们分别封装了对整数、整数数组、长整型、长整型数组和普通对象的多线程安全操作。 这些都是居于CAS算法实现的。CAS即:Compare and Swap,是比较并交换的意思。 CAS 简介 CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。 非阻塞算法 (nonblocking algorithms) 一个线程的失败或者挂起不应该影响其他线程的失败或挂起的算法。 现代的CPU提供了特殊的指令,可以自动更新共享数据,而且能够检测到其他线程的干扰,而 compareAndSet() 就用这些代替了锁定。 拿出AtomicInteger来研究在没有锁的情况下是如何做到数据正确性的。 private volatile int value; 首先毫无以为,在没有锁的机制下可能需要借助volatile原语,保证线程间的数据是可见的(共享的)。 这样才获取变量的值的时候才能直接读取。 public final int get() { return value; } 然后来看看

CPP(c++) 原子操作

主宰稳场 提交于 2020-01-10 17:43:56
C++中对共享数据的存取在并发条件下可能会引起data race的undifined行为,需要限制并发程序以某种特定的顺序执行, 有两种方式:使用mutex保护共享数据,原子操作:针对原子类型操作要不一步完成,要么不做,不可能出现操作一半被切换CPU, 这样防止由于多线程指令交叉执行带来的可能错误。非原子操作下,某个线程可能看见的是一个其它线程操作未完成的数据。 std::atomic:例子 class Test { public: Test() = default; void CThreadFunc() { for (int i = 0; i < 10000; ++i) { //std::lock_guard<std::mutex> lck(Test::m_s_ivalue_mutex); //m_iValue需要加锁才可正常工作 m_iValue++; m_atomic_value++; //不加锁,也可正常工作 } } void Start() { std::vector<std::thread> threads; for (int i = 0; i < 10; ++i) { threads.push_back(std::thread(&Test::CThreadFunc, this)); } for (auto& th : threads) { if (th

并发编程的基石——CAS机制

折月煮酒 提交于 2020-01-10 04:11:46
本博客系列是学习并发编程过程中的记录总结。由于文章比较多,写的时间也比较散,所以我整理了个目录贴(传送门),方便查阅。 并发编程系列博客传送门 Java中提供了很多原子操作类来保证共享变量操作的原子性。这些原子操作的底层原理都是使用了CAS机制。在使用一门技术之前,了解这个技术的底层原理是非常重要的,所以本篇博客就先来讲讲什么是CAS机制,CAS机制存在的一些问题以及在Java中怎么使用CAS机制。 其实Java并发框架的基石一共有两块,一块是本文介绍的CAS,另一块就是AQS,后续也会写博客介绍。 什么是CAS机制 CAS机制是一种数据更新的方式。在具体讲什么是CAS机制之前,我们先来聊下在多线程环境下,对共享变量进行数据更新的两种模式:悲观锁模式和乐观锁模式。 悲观锁更新的方式认为:在更新数据的时候大概率会有其他线程去争夺共享资源,所以悲观锁的做法是:第一个获取资源的线程会将资源锁定起来,其他没争夺到资源的线程只能进入阻塞队列,等第一个获取资源的线程释放锁之后,这些线程才能有机会重新争夺资源。synchronized就是 java 中悲观锁的典型实现,synchronized使用起来非常简单方便,但是会使没争抢到资源的线程进入阻塞状态,线程在阻塞状态和Runnable状态之间切换效率较低(比较慢)。比如你的更新操作其实是非常快的

JUC 中的 Atomic 原子类总结

∥☆過路亽.° 提交于 2020-01-10 00:11:16
1 Atomic 原子类介绍 Atomic 翻译成中文是原子的意思。在化学上,我们知道原子是构成一般物质的最小单位,在化学反应中是不可分割的。在我们这里 Atomic 是指一个操作是不可中断的。即使是在多个线程一起执行的时候,一个操作一旦开始,就不会被其他线程干扰。 所以,所谓原子类说简单点就是具有原子/原子操作特征的类。 并发包 java.util.concurrent 的原子类都存放在 java.util.concurrent.atomic 下,如下图所示。 根据操作的数据类型,可以将JUC包中的原子类分为4类 基本类型 使用原子的方式更新基本类型 AtomicInteger:整型原子类 AtomicLong:长整型原子类 AtomicBoolean :布尔型原子类 数组类型 使用原子的方式更新数组里的某个元素 AtomicIntegerArray:整型数组原子类 AtomicLongArray:长整型数组原子类 AtomicReferenceArray :引用类型数组原子类 引用类型 AtomicReference:引用类型原子类 AtomicReferenceFieldUpdater:原子更新引用类型里的字段 AtomicMarkableReference :原子更新带有标记位的引用类型 对象的属性修改类型 AtomicIntegerFieldUpdater

原子类型字段更新器AtomicXxxxFieldUpdater

老子叫甜甜 提交于 2020-01-08 19:45:51
本博客系列是学习并发编程过程中的记录总结。由于文章比较多,写的时间也比较散,所以我整理了个目录贴(传送门),方便查阅。 并发编程系列博客传送门 原子类型字段更新器 在 java.util.concurrent.atomic 中,原子类型字段更新器有以下三种: AtomicIntegerFieldUpdater:基于反射的工具类,可以原子性的更新指定对象的指定int类型字段。 AtomicLongFieldUpdater:基于反射的工具类,可以原子性的更新指定对象的指定long类型字段。 AtomicReferenceFieldUpdater:基于反射的工具类,可以原子性的更新指定对象的指定应用类型字段。 使用规则 原子类型字段更新器在内部通过Unsafe类的native方法保证操作的原子性。 关于原子类型字段更新器的使用需要注意以下几个方面: 字段必须是volatile类型的,用于保证可见性。 字段和字段更新器的访问类型(public/protected/private)必须一致。 字段只能是实例变量,不能是类变量(static)。 字段不能是final的变量,这样的字段不可修改。 如果要处理Integer和Long类型,则需要使用AtomicReferenceFieldUpdater 使用列子(以AtomicIntegerFieldUpdater为列) public class

并发编程的灵魂:CAS机制详解

生来就可爱ヽ(ⅴ<●) 提交于 2020-01-08 18:43:51
Java中提供了很多原子操作类来保证共享变量操作的原子性。这些原子操作的底层原理都是使用了CAS机制。在使用一门技术之前,了解这个技术的底层原理是非常重要的,所以本篇文章就先来讲讲什么是CAS机制,CAS机制存在的一些问题以及在Java中怎么使用CAS机制。 其实Java并发框架的基石一共有两块,一块是本文介绍的CAS,另一块就是AQS,后续也会写文章介绍。 什么是CAS机制 CAS机制是一种数据更新的方式。在具体讲什么是CAS机制之前,我们先来聊下在多线程环境下,对共享变量进行数据更新的两种模式:悲观锁模式和乐观锁模式。 悲观锁更新的方式认为:在更新数据的时候大概率会有其他线程去争夺共享资源,所以悲观锁的做法是:第一个获取资源的线程会将资源锁定起来,其他没争夺到资源的线程只能进入阻塞队列,等第一个获取资源的线程释放锁之后,这些线程才能有机会重新争夺资源。synchronized就是java中悲观锁的典型实现,synchronized使用起来非常简单方便,但是会使没争抢到资源的线程进入阻塞状态,线程在阻塞状态和Runnable状态之间切换效率较低(比较慢)。比如你的更新操作其实是非常快的,这种情况下你还用synchronized将其他线程都锁住了,线程从Blocked状态切换回Runnable华的时间可能比你的更新操作的时间还要长。 乐观锁更新方式认为

ConcurrentHashMap的CAS操作

夙愿已清 提交于 2020-01-08 14:36:27
无锁的概念   在谈论无锁概念时,总会关联起乐观派与悲观派,对于乐观派而言,他们认为事情总会往好的方向发展,总是认为坏的情况发生的概率特别小,可以无所顾忌地做事,但对于悲观派而已,他们总会认为发展事态如果不及时控制,以后就无法挽回了,即使无法挽回的局面几乎不可能发生。   这两种派系映射到并发编程中就如同加锁与无锁的策略,即加锁是一种悲观策略,无锁是一种乐观策略,因为对于加锁的并发程序来说,它们总是认为每次访问共享资源时总会发生冲突,因此必须对每一次数据操作实施加锁策略。 而无锁则总是假设对共享资源的访问没有冲突,线程可以不停执行,无需加锁,无需等待,一旦发现冲突,无锁策略则采用一种称为CAS的技术来保证线程执行的安全性,这项CAS技术就是无锁策略实现的关键,下面我们进一步了解CAS技术的奇妙之处。 无锁的执行者-CAS 介绍CAS CAS的全称是Compare And Swap 即比较交换,其算法核心思想如下 执行函数:CAS(V,E,N) 其包含3个参数 V表示要更新的变量 E表示预期值 N表示新值 如果V值等于E值,则将V的值设为N。若V值和E值不同,则说明已经有其他线程做了更新,则当前线程什么都不做。 通俗的理解就是CAS操作需要我们提供一个期望值,当期望值与当前线程的变量值相同时,说明还没线程修改该值,当前线程可以进行修改,也就是执行CAS操作,但如果期望值与当前线程不符

AtomicXXX系列类使用分析

巧了我就是萌 提交于 2020-01-08 10:31:20
本博客系列是学习并发编程过程中的记录总结。由于文章比较多,写的时间也比较散,所以我整理了个目录贴(传送门),方便查阅。 并发编程系列博客传送门 在 java.util.concurrent.atomic 中,普通的原子类型有以下四种: AtomicBoolean:提供对基本数据类型boolean的原子性更新操作。 AtomicInteger:提供对基本数据类型int的原子性更新操作。 AtomicLong:提供对基本数据类型long的原子性更新操作。 AtomicReference :这是一个泛型类,提供对引用类型的原子性更新操作。 数组相关的操作类有: AtomicLongArray:提供对int[]数组元素的原子性更新操作。 AtomicIntegerArray:提供对long[]数组元素的原子性更新操作。 AtomicReferenceArray:提供对引用类型[]数组元素的原子性更新操作。 由于上面的原子操作类的实现原理差不多,我们这边就选择 AtomicInteger 来分析。 代码分析 构造函数 public class AtomicInteger extends Number implements java.io.Serializable { private static final long serialVersionUID =

Atomic系列类整体介绍

╄→尐↘猪︶ㄣ 提交于 2020-01-07 12:26:20
本博客系列是学习并发编程过程中的记录总结。由于文章比较多,写的时间也比较散,所以我整理了个目录贴(传送门),方便查阅。 并发编程系列博客传送门 本文是转载文章,原文请见 此博客 ,文章主要对 java.util.concurrent.atomic 开发包下的类进行整体概述与类别划分。 版本说明 在JDK1.5版本之前,多行代码的原子性主要通过synchronized关键字进行保证。 在JDK1.5版本,Java提供了原子类型专门确保变量操作的原子性。 开发包整体说明 原子类型位于java.util.concurrent.atomic包下,其主要类如下: 其类图关系如下: 原子类型划分 为了方面对这些类逐级掌握,我将这些原子类型分为以下几类: 普通原子类型:提供对boolean、int、long和对象的原子性操作。 AtomicBoolean AtomicInteger AtomicLong AtomicReference 原子类型数组:提供对数组元素的原子性操作。 AtomicLongArray AtomicIntegerArray AtomicReferenceArray 原子类型字段更新器:提供对指定对象的指定字段进行原子性操作。 AtomicLongFieldUpdater AtomicIntegerFieldUpdater