一. Java volatile
volatile关键字可保证变量可见性,但是无法保证原子性,下面演示多线程修改共享变量Count场景。
/** * 共享变量在多线程下修改测试 */ public class NonAtomicTest extends Thread { public static volatile int count = 0; public void increase(){ count++; } public void run(){ for(int i=0; i<10000; i++){ increase(); } } // main public static void main(String[] args) { Thread[] ths = new NonAtomicTest[20]; for(int i=0; i<ths.length; i++){ ths[i] = new NonAtomicTest(); ths[i].start(); } while(Thread.activeCount() > 1){ Thread.yield(); } System.out.println("Val: "+ count); } }
执行上述代码,发现每次执行count的值都不同,均小于200000。原因count++非原子操作,字节码执行过程:
GETSTATIC count // 从内存加载count到栈 ICONST_1 // 从栈中读取count值 IADD // 执行加法 PUTSTATIC count // 将执行结果存储至内存
对于上述问题,可对线程执行体加锁同步访问,但是加锁开销较大。Java中提供了AutomicInteger, AutomicLong 等原子操作类来处理上述问题,也是目前比较流行的无锁编程。原子操作由底层硬件 cmpxchg 指令支持,Linux 内核大量使用该指令。C++11也单独提供了原子类。
二. C++ 无锁编程
Linux下也提供原子操作API,C++11 std::aomic<T>模板均可进行无锁编程。
#include <iostream> #include <vector> #include <thread> #include <atomic> #include <mutex> /// main int main(int argc, char **argv) { static volatile int Count = 0; std::mutex mutex; // 方案一:互斥锁 auto fn1 = [&mutex, &Count] { for (int i=0; i<10000; i++) { std::lock_guard<std::mutex> lock(mutex); Count++; } }; // 方案二:原子操作接口 auto fn2 = [&Count] { for (int i=0; i<10000; i++) { __sync_fetch_and_add(&Count, 1); //__atomic_add_fetch(&Count, 1, __ATOMIC_SEQ_CST); } }; static std::atomic<int> Count(0); // 方案三:原子类 auto fn3 = [&Count] { for (int i=0; i<10000; i++) { std::atomic_fetch_add(&Count, 1); } }; /// std::vector<std::thread> threads; // 启动20个线程 for(int i=0; i<20; i++) { threads.push_back(std::thread(fn2)); } // 等待线程执行完成 for (auto &th : threads) { th.join(); } std::cout << "Val: " << Count << std::endl; return 0; }
g++ -o test test.c -std=c++11 -lpthread
上述三种方案均可打印200000
相关推荐
分布式Redis原子操作示例,近期项目中遇到分布式项目中多节点大并发操作redis同一个key。此案例利用java调用LUA脚本实现redis操作的原子性。分享出来大家参考。
串口方式:用串口接收中断方式接收,不是DMA. 遇到的问题:串口数据有帧丢失。 原因描述:在串口接收中断中接收到字节时变量size...实际的原因是对size的操作不是原子操作的,具体更改见文档。有相关程序和具体的分析。
在kotlin中使用原子操作的惯用方法。
多线程程序中的原子操作
C++多线程原子操作实现方法。很很详解!
原子操作、信号量、读写信号量和自旋锁的API.希望能帮助大家
测试了windows下原子操作api的使用,很简单的测试,还是比较有趣的
1.认识原子操作 原子操作就是在多线程程序中“最小的且不可并行化的”操作,意味着多个线程访问同一个资源时,有且仅有一个线程能对资源进行操作。通常情况下原子操作可以通过互斥的访问方式来保证,例如Linux下的...
NULL 博文链接:https://peter8015.iteye.com/blog/975250
同步之原子操作.pptx
各位只需要将CLib4Swift.h、CLib4Swift.c以及SwiftAtomic.swift三个文件放入到自己项目工程中即可,然后还需要将"CLib4Swift.h"头文件include到你的brdige头文件中。 具体使用非常简单,直接看main.swift中的测试...
atomic_ops原子操作1
原子操作 四种原子更新方式文档,分别是原子更新基本类型,原子更 新数组,原子更新引用和原子更新字段。Atomic包里的类基本都是使用Unsafe实现的包装 类
MongoDB原子操作.pdf 学习资料 复习资料 教学资源
linux下原子操作程序源码
原子操作类, 发容器 & 并发工具, 线程池, 并发实践 Java是一种面向对象的编程语言,由Sun Microsystems于1995年推出。它是一种跨平台的语言,意味着可以在不同的操作系统上运行。Java具有简单、可移植、高性能和...
MongoDB原子操作与GridFS.pdf 学习资料 复习资料 教学资源
如两个线程操作同一变量过程中,一个线程执行过程中可能被内核临时挂起,这就是线程切换,当内核再次切换到该线程时,之前的数据可能已被修改,不能保证原子操作。 C++11提供了个原子的类和方法atomic,保证了多线程...
Linux驱动并发控制之位原子操作.pdf