原子操作

05. redis事务

谁说我不能喝 提交于 2020-02-17 08:03:25
目录 Redis 事务 事务 1. 命令有序 2. 始终原子 开启使用事务 Redis事务中出现错误 1. EXEC前的错误 2. EXEC后的错误 为什么出错了不支持roll backs? Redis的乐观锁实现check-and-set 小结 Redis 事务 Redis操作时支持事务的。事务具有原子性atomic,包含在事务中的操作要么都执行成功,要么都执行失败。但是redis不支持回滚,但是可以在测试开发环节避免错误操作。可以说原子性上是半支持的,看后面原因。 很多时候我们需要进行事务操作。 翻译官档: https://redis.io/topics/transactions 实际操作:python版使用参考 https://github.com/7Edge/redis-demo/blob/master/redis_pipeline.py 事务 MULTI, EXEC, DISCARD 和 WATCH 操作都是redis事务的基础操作。这些操作可以让一组操作看作一个操作原子执行。之所以能做到,是因为一下两个重要的保障: 1. 命令有序 在事务中的所有命令都是有序的,且执行是顺序执行的。当另一个客户端连接发生错误,是不可能影响到当前正在执行的事务的。这点就保证了命令执行时是相互隔离的操作。因为是单线程,且redisserver利用i/o多路复用来处理并发连接。 2. 始终原子

C语言/原子/编译,你真的明白了吗?

本秂侑毒 提交于 2020-02-14 04:24:06
  版权申明:本文为博主窗户(Colin Cai)原创,欢迎转帖。如要转贴,必须注明原文网址   http://www.cnblogs.com/Colin-Cai/p/7668982.html   作者:窗户   QQ:6679072   E-mail:6679072@qq.com   说到原子,类似于以下的代码可能人人都可以看出猫腻。 /* http://www.cnblogs.com/Colin-Cai */ #include <stdio.h> #include <pthread.h> int cnt = 0; void* mythread(void* arg) { int i; for(i=0;i<500000000;i++) cnt++; return NULL; } int main() { pthread_t id, id2; pthread_create(&id, NULL, mythread, NULL); pthread_create(&id2, NULL, mythread, NULL); pthread_join(id, NULL); pthread_join(id2, NULL); printf("cnt = %d\n", cnt); return 0; }   我想大多数人都知道其结果未必会得到1000000000。   测试一下吧。 linux

linux设备驱动编程之并发控制

谁都会走 提交于 2020-02-12 04:44:48
1.什么是并发? (1)什么是并发? 所谓的并发控制便是多个进程同时进行,并行的对内核资源(全局变量,静态变量等)访问而出现竞态。竞态简单的说就是两个或两个以上的进程同时访问一个资源,同时引起资源的错误. 例如:如下图,按照进程1代码逻辑设计意图,赋值进程变量a为100,并且执行代码x,但是就在这时候进程1不知道进程2也在并发访问全局变量a并赋值为200,这样以来那么进程1的代码并不会执行.程序出现意想不到的错误.而这就是并发访问导致的错误. 2.并发的原因? 并发的原因有种,主要包含如下 (1)对称多处理器(smp)多个cpu 如下图,当多个cpu同时访问一个全局变量的时候便会出现静态 (2)单个cpu抢占其他进程 当一个进程资源在自己的时间戳片消耗完成或者被其他高优先级进程抢占后访问其共享资源变回类似与smp.因为linux内核有着"宏观串行,微观串行"的执行流程. (3)中断 当进程正在访问共享资源的时候,由于中断打断了,并且中断服务程序也对共享资源进行访问导致了竞态. (4)编译乱序以及执行乱系 (这个后续比较复杂,后续有时间再做笔记解说) 3.并发控制的方法 为了避免上面的并发访问导致了竟态,我们控制并发的方法很简单,当一个进程访问共享资源之前,需要加一把锁或者一个访问状态,告诉其他进程当前进程正在访问,需要排队等待

Think In Java 21.3.5 临界区

做~自己de王妃 提交于 2020-02-10 17:33:04
有时,你只是希望防止多个线程同时访问方法内部的部分代码而不是防止访问整个方法。通过这种方式分离出来的代码段被称为 临界区(critical section) ,它也使用synchronized关键字建立。这里,synchronized被用来指定某个对象,此对象的锁被用来对花括号内的代码进行同步控制: synchronized(syncObject){ // This code can be accessed by only one task at a time } 这也被称为 同步控制块 ;在进入此段代码前,必须得到syncObject对象的锁。如果其他线程已经得到这个锁,那么就得等到锁被释放以后,才能进入临界区。 通过使用同步控制块,而不是对整个方法进行同步控制,可以使多个任务访问对象的时间性能得到显著提高,下面的例子比较了这两种同步控制方法。此外,它也演示了如何把一个非保护类型的类,在其他类的保护和控制之下,应用于多线程的环境: package lime.tij._021._003._005; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.ExecutorService; import java.util

redis分布式锁递进方案

爱⌒轻易说出口 提交于 2020-02-09 23:26:37
什么是分布式锁 在学习Java多线程编程的时候,锁是一个很重要也很基础的概念,锁可以看成是多线程情况下访问共享资源的一种线程同步机制。这是对于单进程应用而言的,即所有线程都在同一个JVM进程里的时候,使用Java语言提供的锁机制可以起到对共享资源进行同步的作用。如果分布式环境下多个不同线程需要对共享资源进行同步,那么用Java的锁机制就无法实现了,这个时候就必须借助分布式锁来解决分布式环境下共享资源的同步问题。分布式锁有很多种解决方案,今天我们要讲的是怎么使用缓存数据库Redis来实现分布式锁。 Redis分布式锁方案一 使用Redis实现分布式锁最简单的方案是在获取锁之前先查询一下以该锁为key对应的value存不存在,如果存在,则说明该锁被其他客户端获取了,否则的话就尝试获取锁,获取锁的方法很简单,只要以该锁为key,设置一个随机的值就行了。比如,我们有一批任务需要由多个分布式线程处理,每个任务都有一个taskId,为了保证每个任务只被执行一次,在工作线程执行任务之前,先获取该任务的锁,锁的key可以为taskId。因此,获取锁的过程可以用如下伪代码实现: 上述就是最简单的获取锁的方案了,但是大家可以想想这个方案有什么问题呢?有没有什么潜在的坑?在分析这种方案的优缺点之前,先说一下获取锁后我们一般是怎么使用锁,并且又是如何释放锁的,以Java语言为例

并发编程之原子类

半腔热情 提交于 2020-02-07 00:49:17
Java从JDK 1.5开始提供了java.util.concurrent.atomic包(以下简称Atomic包),这个包中 的原子操作类提供了一种用法简单、性能高效、线程安全地更新一个变量的方式。 🐤 内部都是采用CAS+volatile实现了无锁并发 这节不讲原理,只讲如何使用。 整体结构 从整体上可以分为5组,分别进行说明 ↘️ 基本类型 使用原子的方式更新基本类型 AtomicInteger:整形原子类 AtomicLong:长整型原子类 AtomicBoolean :布尔型原子类 数组类型 使用原子的方式更新数组里的某个元素 AtomicIntegerArray:整形数组原子类 AtomicLongArray:长整形数组原子类 AtomicReferenceArray :引用类型数组原子类 引用类型 AtomicReference:引用类型原子类 AtomicStampedRerence:原子更新引用类型里的字段原子类 AtomicMarkableReference :原子更新带有标记位的引用类型 对象的属性修改类型 AtomicIntegerFieldUpdater:原子更新整形字段的更新器 AtomicLongFieldUpdater:原子更新长整形字段的更新器 AtomicStampedReference :原子更新带有版本号的引用类型。该类将整数值与引用关联起来

Java如何实现原子操作

不打扰是莪最后的温柔 提交于 2020-02-07 00:28:30
在Java中可以通过锁和循环CAS的方式来实现原子操作。 (1)使用循环CAS实现原子操作 ​ JVM中的CAS操作正是利用了处理器提供的CMPXCHG指令实现的。自旋CAS实现的基本思路就是循环进行CAS操作直到成功为止。 (2)使用锁机制实现原子操作 ​ 锁机制保证了只有获得锁的线程才能够操作锁定的内存区域。JVM内部实现了很多种锁机制,有偏向锁、轻量级锁和互斥锁。有意思的是除了偏向锁,JVM实现锁的方式都用了循环CAS,即当一个线程想进入同步块的时候使用循环CAS的方式来获取锁,当它退出同步块的时候使用循环CAS释放锁。 来源: CSDN 作者: 徐海兴 链接: https://blog.csdn.net/u012326462/article/details/104201760

C++ 内存模型

余生颓废 提交于 2020-02-06 03:19:45
C++ std::atomic 原子类型 原子操作:一个不可分割的操作。 标准原子类型可以在 头文件之中找到,在这种类型上的所有操作都是原子的。它们都有一个 is_lock_free() 的成员函数,让用户决定在给定类型上的操作是否用原子指令完成。唯一不提供 is_lock_free() 成员函数的类型是 std::atomic_flag ,在此类型上的操作要求是无锁的。可以利用 std::atomic_flag 实现一个简单的锁。 #include <iostream> #include <thread> #include <atomic> #include <assert.h> class spinlock_mutex { public: spinlock_mutex() : flag_(ATOMIC_FLAG_INIT) { } void lock() { while(flag_.test_and_set(std::memory_order_acquire)) ; } void unlock() { flag_.clear(std::memory_order_release); } private: std::atomic_flag flag_; }; int value = 0; spinlock_mutex mutex; void test_function() {

Redis的事务功能详解

£可爱£侵袭症+ 提交于 2020-02-05 14:04:41
Redis的事务功能详解 MULTI、EXEC、DISCARD和WATCH命令是Redis事务功能的基础 。Redis事务允许在一次单独的步骤中执行一组命令,并且可以保证如下两个重要事项: > Redis会将一个事务中的所有命令序列化 ,然后按顺序执行。Redis不可能在一个Redis事务的执行过程中插入执行另一个客户端发出的请求。这样便能保证Redis将这些命令作为一个单独的隔离操作执行。 > 在一个Redis事务中,Redis要么执行其中的所有命令,要么什么都不执行 。 因此,Redis事务能够保证原子性 。EXEC命令会触发执行事务中的所有命令。因此,当某个客户端正在执行一次事务时,如果它在调用MULTI命令之前就从Redis服务端断开连接,那么就不会执行事务中的任何操作;相反,如果它在调用EXEC命令之后才从Redis服务端断开连接,那么就会执行事务中的所有操作。当Redis使用只增文件(AOF:Append-only File)时,Redis能够确保使用一个单独的write(2)系统调用,这样便能将事务写入磁盘。然而,如果Redis服务器宕机,或者系统管理员以某种方式停止Redis服务进程的运行,那么Redis很有可能只执行了事务中的一部分操作。Redis将会在重新启动时检查上述状态,然后退出运行,并且输出报错信息。使用redis-check

Linux进程同步机制-Futex

纵然是瞬间 提交于 2020-02-05 02:43:21
引子 在编译2.6内核的时候,你会在编译选项中看到[*] Enable futex support这一项,上网查,有的资料会告诉你"不选这个内核不一定能正确的运行使用glibc的程序",那futex是什么?和glibc又有什么关系呢? futex诞生之前 在futex诞生之前,linux下的同步机制可以归为两类:用户态的同步机制 和 内核同步机制。 用户态的同步机制基本上就是利用原子指令实现的spinlock。最简单的实现就是使用一个整型数,0表示未上锁,1表示已上锁。trylock操作就利用原子指令尝试将0改为1: bool trylock ( int lockval ) { int old ; atomic { old = lockval ; lockval = 1 ; } // 如:x86下的xchg指令 return old == 0 ; } spinlock的lock操作则是一个死循环,不断尝试trylock,直到成功。 对于一些很小的临界区,使用spinlock是很高效的。因为trylock失败时,可以预期持有锁的线程(进程)会很快退出临界区(释放锁)。所以死循环的忙等待很可能要比进程挂起等待更高效。 但是spinlock的应用场景有限,对于大的临界区,忙等待则是件很恐怖的事情,特别是当同步机制运用于等待某一事件时(比如服务器工作线程等待客户端发起请求)