一. 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
相关推荐
### STM32串口变量的原子操作问题详解 #### 一、问题背景及描述 在进行STM32单片机的串口通信开发过程中,可能会遇到串口数据帧丢失的问题。这种现象通常表现为:尽管串口接收到了完整的数据包(如512个字节或1024...
### 多线程程序中的原子操作 #### 一、引言 在多线程编程中,原子操作是一个至关重要的概念。原子操作指的是不可再分割的操作,即在一个操作执行的过程中不会被其他线程打断。这对于保证多线程程序的正确性和避免...
分布式Redis原子操作示例,近期项目中遇到分布式项目中多节点大并发操作redis同一个key。此案例利用java调用LUA脚本实现redis操作的原子性。分享出来大家参考。
Kotlinx.AtomicFu是Kotlin社区的一个开源项目,它提供了在Kotlin中使用原子操作(Atomic Operations)的简便工具和库。这个项目主要是为了解决多线程环境下的并发问题,尤其是在非Java平台如JavaScript或者Native上...
在C++编程中,多线程环境下的原子操作(Atomic Operations)是确保程序并发执行时数据一致性的重要机制。原子操作是指不可分割的操作,一旦开始执行,就不会被其他线程中断,直到该操作完成。在多线程环境中,不使用...
在Windows平台上,C++编程中使用原子操作(Atomic Operations)是为了保证多线程环境下的数据一致性,避免竞态条件和死锁等问题。原子操作是指在多线程环境下,该操作会被完整无中断地执行,不会被其他线程打断。...
### 原子操作、信号量、读写信号量和自旋锁的API详解 #### 一、引言 在现代操作系统中,特别是在多处理器环境下,确保数据的一致性和完整性至关重要。为此,Linux内核提供了多种同步机制来保护共享资源免受并发...
在Java多线程编程中,原子操作是一种非常关键的概念,它涉及到并发控制和线程安全。原子操作是指在不被其他线程中断的情况下,能够完整执行的一个或一系列操作。这样的操作在多线程环境中可以保证数据的一致性和完整...
本文档详细介绍了并发编程中的原子操作,特别是Java语言中通过CAS(Compare-And-Swap)实现的原子操作,并指出了在实际编程中如何使用和实现原子操作。 首先,文档开篇就介绍了原子操作的定义。所谓原子操作,指的...
ARM 原子操作与同步机制 ARM 架构中的原子操作是指在多处理器系统中,确保对共享资源的访问是安全、可靠和高效的操作。原子操作是指在执行某个操作时,不允许其他处理器或线程干扰或中断该操作,直到该操作完成。 ...
原子操作 atomic_ops 介绍 atomic_ops 是 Linux 内核中的一种原子操作,用于实现原子 counter、Bit 操作和 spinlock 接口。下面将对 atomic_ops 的原子操作进行详细介绍。 atomic_t 类型 atomic_t 是一种原子...
本文将详细介绍C++中的原子操作,包括其基本概念、使用场景、API以及如何利用原子操作来避免竞态条件和死锁。 原子操作是C++并发编程中的重要特性,它们为开发者提供了一种高效、灵活且线程安全的方法来处理并发问题...
在处理并发操作和数据更新时,MongoDB 提供了原子性保障,确保在单个文档级别的操作是不可分割的,即原子操作。虽然 MongoDB 不支持跨文档的事务,但对单个文档的修改、保存和删除等操作都是原子性的,保证了数据的...
Linux 驱动并发控制之位原子操作 本文主要讲述 Linux 驱动并发控制中的位原子操作,包括其原理、常用的位原子操作函数、设备注册、驱动源码文件等。 一、位原子操作的原理 位原子操作是利用位操作来实现并发控制...
在Linux系统中,原子操作(Atomic Operations)是编程中一种重要的技术,特别是在多线程和并发环境下,确保数据的一致性和完整性。它们提供了一种在不使用锁的情况下更新变量的方法,避免了竞态条件和死锁的问题。在...
1.认识原子操作 原子操作就是在多线程程序中“最小的且不可并行化的”操作,意味着多个线程访问同一个资源时,有且仅有一个线程能对资源进行操作。通常情况下原子操作可以通过互斥的访问方式来保证,例如Linux下的...
C++11引入了原子操作(Atomic Operations)作为标准库的一部分,这为多线程编程提供了重要的支持。原子操作在并发环境下确保了数据的完整性,防止了数据竞争和其他并发问题。下面将详细介绍C++11中`std::atomic`的...
AtomicInteger 是Java并发编程中实现原子操作的重要工具。它通过 Unsafe 类提供的硬件级别的原子操作和 volatile 关键字保证了操作的原子性和可见性。在实际开发中,我们应该根据具体的应用场景选择合适的同步机制。...