Rust Atomics and Locks 源码解读

目录
  • 正文
    • load 和 store
    • 使用 AtomicBool实现通知线程停止的案例

正文

在 Rust 中,原子性操作是指在多线程并发环境下对共享数据进行操作时,保证操作的原子性,即不会出现数据竞争等问题。Rust 提供了原子类型和原子操作来支持多线程并发编程。

Rust 的原子类型包括 AtomicBoolAtomicIsizeAtomicUsizeAtomicPtr 等。这些类型的实现都使用了底层的原子操作指令,保证了它们的读写操作是原子的,不会被其他线程中断。

在 Rust 中,原子操作由 std::sync::atomic 模块提供。该模块提供了一系列原子操作函数,包括:

  • load:原子读取一个原子类型的值。
  • store:原子写入一个原子类型的值。
  • swap:原子交换一个原子类型的值。
  • compare_and_swap:原子比较并交换一个原子类型的值。
  • fetch_addfetch_subfetch_andfetch_orfetch_xor 等:原子地对一个原子类型进行加减、位运算等操作。

需要注意的是,原子操作并不是万能的,不能完全避免所有的数据竞争问题。例如,如果多个线程都对同一个原子类型进行操作,就有可能出现ABA问题。为了避免这种问题,Rust 还提供了 std::sync::Arcstd::sync::Mutexstd::sync::RwLock 等同步原语,可以更好地保证线程安全。

总之,Rust 的原子类型和原子操作可以让我们在多线程并发编程中更加安全和高效地操作共享数据。但需要注意,正确地使用原子类型和原子操作需要对并发编程有深刻的理解,并避免过度依赖原子操作来避免竞态条件。

load 和 store

loadstore 是原子类型的两个基本操作函数。load 函数用于原子地读取一个原子类型的值,而 store 函数用于原子地写入一个原子类型的值。

下面是具体的代码案例:

use std::sync::atomic::{AtomicI32, Ordering};
fn main() {
    // 创建一个原子整数类型,并设置初始值为 42
    let counter = AtomicI32::new(42);
    // 原子地读取计数器的值
    let value = counter.load(Ordering::Relaxed);
    println!("counter value: {}", value);
    // 原子地将计数器的值增加 10
    counter.store(value + 10, Ordering::Relaxed);
    // 原子地读取计数器的新值
    let new_value = counter.load(Ordering::Relaxed);
    println!("new counter value: {}", new_value);
}

在这个例子中,我们创建了一个原子整数类型 AtomicI32,并设置初始值为 42。接着,我们使用 load 函数原子地读取了计数器的值,并使用 store 函数原子地将计数器的值增加 10。最后,我们又使用 load 函数原子地读取了计数器的新值,并打印输出。

需要注意的是,loadstore 函数都需要指定一个 Ordering 参数。Ordering 参数用于指定原子操作的内存顺序,可以控制不同线程之间的操作顺序,以及对其他共享变量的影响。具体来说,Ordering 参数有以下几种取值:

  • Relaxed:表示对内存顺序没有任何要求。
  • Acquire:表示读取操作需要获取锁或同步,用于同步其他线程对内存的修改。
  • Release:表示写入操作需要释放锁或同步,用于同步其他线程对内存的读取。
  • AcqRel:表示既需要获取锁或同步,又需要释放锁或同步。
  • SeqCst:表示需要严格按照顺序执行所有原子操作。

一般来说,使用 Relaxed 内存顺序可以获得最好的性能,但可能会出现一些意想不到的行为。而使用 SeqCst 内存顺序可以获得最严格的同步语义,但也会牺牲一些性能。具体使用哪种内存顺序需要根据具体情况进行权衡。

使用 AtomicBool实现通知线程停止的案例

use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::thread;
fn main() {
    // 创建一个原子布尔类型,并设置初始值为 false
    let running = Arc::new(AtomicBool::new(true));
    // 创建一个新线程,用于执行耗时的操作
    let running_clone = Arc::clone(&running);
    let handle = thread::spawn(move || {
        loop {
            // 检查是否需要停止运行
            if !running_clone.load(Ordering::Relaxed) {
                break;
            }
            // 执行耗时的操作
            println!("working...");
            // 模拟耗时操作
            thread::sleep(std::time::Duration::from_secs(1));
        }
    });
    // 等待一段时间后通知线程停止运行
    thread::sleep(std::time::Duration::from_secs(5));
    running.store(false, Ordering::Relaxed);
    // 等待线程执行完毕
    handle.join().unwrap();
}

在这个例子中,我们创建了一个原子布尔类型 AtomicBool,并设置初始值为 true。接着,我们创建了一个新线程,用于执行耗时的操作。在循环中,我们首先检查 running 变量的值,如果为 false,则退出循环,停止运行。否则,我们执行耗时的操作,并模拟一秒钟的等待时间。

在主线程中,我们等待 5 秒钟后,将 running 变量的值设为 false,通知线程停止运行。最后,我们等待线程执行完毕,并调用 join 方法等待线程结束。

需要注意的是,我们在设置 running 变量的值时使用了 Ordering::Relaxed,这意味着对 running 变量的修改不需要同步到其他线程中。在这个例子中,由于只有一个线程在修改 running 变量的值,因此使用 Relaxed 订单是安全的。如果在实际代码中需要更强的同步保证,应该使用更高级别的 Ordering 订单,例如 Ordering::AcquireOrdering::Release

以上就是Rust Atomics and Locks 源码解读的详细内容,更多关于Rust Atomics源码的资料请关注我们其它相关文章!

(0)

相关推荐

  • 详解go中panic源码解读

    panic源码解读 前言 本文是在go version go1.13.15 darwin/amd64上进行的 panic的作用 panic能够改变程序的控制流,调用panic后会立刻停止执行当前函数的剩余代码,并在当前Goroutine中递归执行调用方的defer: recover可以中止panic造成的程序崩溃.它是一个只能在defer中发挥作用的函数,在其他作用域中调用不会发挥作用: 举个栗子 package main import "fmt" func main() { fmt.

  • [转]prototype 源码解读 超强推荐第1/3页

    复制代码 代码如下: Prototype is a JavaScript framework that aims to ease development of dynamic web applications. Featuring a unique, easy-to-use toolkit for class-driven development and the nicest Ajax library around, Prototype is quickly becoming the codeb

  • Bootstrap源码解读网格系统(3)

    源码解读Bootstrap网格系统 工作原理 数据行(.row)必须包含在容器(.container)中,以便为其赋予合适的对齐方式和内距(padding).如: <div class="container"> <div class="row"></div> </div> .container的实现源码: .container { padding-right: 15px; padding-left: 15px; mar

  • Ajax::prototype 源码解读

    AJAX之旅(1):由prototype_1.3.1进入javascript殿堂-类的初探  还是决定冠上ajax的头衔,毕竟很多人会用这个关键词搜索.虽然我认为这只是个炒作的概念,不过不得不承认ajax叫起来要方便多了.所以ajax的意思我就不详细解释了. 写这个教程的起因很简单:经过一段时间的ajax学习,有一些体会,并且越发认识到ajax技术的强大,所以决定记录下来,顺便也是对自己思路的整理.有关这个教程的后续,请关注http://www.x2design.net 前几年,javascri

  • Bootstrap源码解读按钮(5)

    源码解读Bootstrap按钮 按钮组 按钮组和下拉菜单组件一样,需要依赖于bootstrap.js.使用"btn-group"的容器,把多个按钮放到这个容器中.例如:<div class="btn-group">...</div> "btn-group"容器里除了可以使用<button>元素之外,还可以使用其他标签元素,比如<a>标签.不过这里面的标签元素需要带有类名".btn"

  • Bootstrap源码解读导航(6)

    源码解读Bootstrap导航 基础样式 制作导航条主要通过".nav"样式.默认的".nav"样式不提供默认的导航样式,必须附加另外一个样式才会有效,比如"nav-tabs"."nav-pills"之类.例如: <ul class="nav"> <li><a href="##">1</a></li> <li><

  • Bootstrap源码解读排版(1)

    源码解读Bootstrap排版 粗体 可以使用<b>和<strong>标签让文本直接加粗. 例如: <p>我在学习<strong>Bootstrap</strong></p> 源码 b, strong { font-weight: bold; } 斜体 使用标签<em>或<i>来实现. 例如: <p>我在学<i>Bootstrap</i>.</p> 强调相关的类

  • Bootstrap源码解读下拉菜单(4)

    源码解读Bootstrap下拉菜单 基本用法 在使用Bootstrap框架的下拉菜单时,必须调用Bootstrap框架提供的bootstrap.js文件.因为Bootstrap的组件交互效果都是依赖于jQuery库写的插件,所以在使用bootstrap.min.js之前一定要先加载jquery.min.js才会生效果. 使用方法如下: 1. 使用一个名为"dropdown"的容器包裹了整个下拉菜单元素:<div class="dropdown"><

  • Bootstrap源码解读表单(2)

    源码解读Bootstrap表单 基础表单 对于基础表单,Bootstrap并未对其做太多的定制性效果设计,仅仅对表单内的fieldset.legend.label标签进行了定制.主要将这些元素的margin.padding和border等进行了细化设置. 这些元素如果使用了类名"form-control",将会实现一些设计上的定制效果. 1. 宽度变成了100% 2. 设置了一个浅灰色(#ccc)的边框 3. 具有4px的圆角 4. 设置阴影效果,并且元素得到焦点之时,阴影和边框效果会

  • JavaScript Title、alt提示(Tips)实现源码解读

    而对于图片标签img也有一个alt属性可以起到类似的作用.但很显然这种提示框太单调了,为此有人用JavaScript实现了漂亮的提示框效果,这种效果常用在WEB游戏中,其中下图的网易邮箱与迅雷影视页面就用到这种效果,虽然彼此实现效果有些差异,但整体实现思路是不变的.为了方便大家了解实现的细节,以方便定制自己想要的效果,我上网找了一段不错的源码,并对其进行了详细的注释,希望对大家有帮助. 含注释代码: 复制代码 代码如下: /************************************

随机推荐