欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

淺析Rust多線程中如何安全的使用變量

 更新時(shí)間:2025年01月28日 08:36:45   作者:databook  
這篇文章主要為大家詳細(xì)介紹了Rust如何在線程的閉包中安全的使用變量,包括共享變量和修改變量,文中的示例代碼講解詳細(xì),有需要的小伙伴可以參考下

在Rust語言中,一個(gè)既引人入勝又可能帶來挑戰(zhàn)的特性是閉包如何從其所在環(huán)境中捕獲變量,尤其是在涉及多線程編程的情境下。

如果嘗試在不使用move關(guān)鍵字的情況下創(chuàng)建新線程并傳遞數(shù)據(jù)至閉包內(nèi),編譯器將很可能返回一系列與生命周期、借用規(guī)則所有權(quán)相關(guān)的復(fù)雜錯(cuò)誤信息。

不過,這種機(jī)制雖然增加了學(xué)習(xí)曲線,但也確保了內(nèi)存安全與并發(fā)執(zhí)行中的數(shù)據(jù)一致性。

本文我們將探討如何在線程的閉包中安全的使用變量,包括共享變量和修改變量。

1. 向線程傳遞變量

首先,我們構(gòu)造一個(gè)簡單的示例,在線程中正常使用一個(gè)外部的變量,看看Rust中能否正常編譯運(yùn)行。

use std::thread;

fn main() {
    let msg = String::from("Hello World!");

    let handle = thread::spawn(|| {
        // msg 是主線中定義的變量
        println!("{}", msg);
    });

    handle.join().unwrap();
}

例子非常簡單,看著寫法也沒什么問題,在其他編程語言中類似的寫法是沒有問題的。

但是,使用cargo run運(yùn)行時(shí),卻有如下的錯(cuò)誤:

為什么會(huì)有這樣的錯(cuò)誤?這就是Rust在內(nèi)存方面更加嚴(yán)謹(jǐn)?shù)脑颉?/p>

上面Rust的錯(cuò)誤信息中也給出了原因,總結(jié)起來主要有兩點(diǎn):

  • 線程的生命周期:新創(chuàng)建的線程的生命周期有可能超出主函數(shù) main 的執(zhí)行范圍。當(dāng) main 函數(shù)終止時(shí),與之相關(guān)的局部變量(也就是msg)將超出作用域。
  • 不符合借用規(guī)則:在 Rust 中,引用的生命周期不會(huì)超過其所指向數(shù)據(jù)的生命周期,以避免出現(xiàn)懸空引用。如果main提前結(jié)束,那么線程中的msg將成為懸空引用。

修復(fù)的方法很簡單,使用move關(guān)鍵字,將變量的所有權(quán)轉(zhuǎn)移到線程中就可以了。

    let handle = thread::spawn(move || {
        // msg 是主線中定義的變量
        println!("{}", msg);
    });

這樣就可以正常運(yùn)行了。

不過,這樣,主線程中就無法使用變量msg了,比如在main函數(shù)的最后打印msg,會(huì)報(bào)錯(cuò),因?yàn)樗乃袡?quán)已經(jīng)轉(zhuǎn)移到線程中了。

2. 多線程共享變量引用

如果我們只把變量的引用轉(zhuǎn)移給線程,是不是可以在主線程main中繼續(xù)使用變量msg呢?

use std::thread;

fn main() {
    let msg = String::from("Hello World!");
    let msg_ref = &msg;

    let handle = {

        thread::spawn(move || {
            // msg 是主線中定義的變量
            println!("{}", msg_ref);
        })
    };

    handle.join().unwrap();

    println!("msg in main : {}", msg_ref);
}

很遺憾,依然有錯(cuò)誤:

錯(cuò)誤的原因仍然是傳入線程中的變量引用msg_ref生命周期的不夠長。

雖然我們使用了move,將msg_ref轉(zhuǎn)移到線程中,但main中仍然擁有底層的數(shù)據(jù)msg,

一旦main函數(shù)結(jié)束(或者數(shù)據(jù)在線程完成之前超出范圍),該引用(msg_ref)指向數(shù)據(jù)將失去有效的內(nèi)存,成為懸空引用。

總的來說就是:

  • 移動(dòng)引用并不移動(dòng)原始數(shù)據(jù)-只轉(zhuǎn)移引用本身的所有權(quán)
  • 實(shí)際數(shù)據(jù)(msg)仍然由原始范圍擁有,并具有自己的生命周期約束

為了修復(fù)這個(gè)錯(cuò)誤,就要用到Rust中提供的并發(fā)原語Arc(一種自動(dòng)引用計(jì)數(shù)的智能指針)。

先看看使用Arc修改后的例子。

use std::sync::Arc;
use std::thread;

fn main() {
    let msg = String::from("Hello World!");
    // 通過Arc來創(chuàng)建變量的引用
    let msg_ref = Arc::new(msg);

    // 線程1
    let handle_1 = {
        // move 之前,先使用Arc clone 變量
        let msg_thread = Arc::clone(&msg_ref);

        thread::spawn(move || {
            println!("Thread 1: {}", msg_thread);
        })
    };

    // 線程2
    let handle_2 = {
        let msg_thread = Arc::clone(&msg_ref);

        thread::spawn(move || {
            println!("Thread 2: {}", msg_thread);
        }) 
    };

    handle_1.join().unwrap();
    handle_2.join().unwrap();

    // 主線程中依然可以使用變量
    println!("msg in main : {}", msg_ref);
}

使用Arc修改之后,變量不僅可以在多個(gè)線程中共享,主線程中也可以使用。

3. 多線程中修改變量

上面的示例是在多個(gè)線程中共享變量,如果想要修改變量的話,那么就會(huì)出現(xiàn)數(shù)據(jù)競爭的情況。

這時(shí),就要用到Rust的另一個(gè)并發(fā)原語Mutex。

use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    // 創(chuàng)建一個(gè)被Mutex保護(hù)的共享數(shù)據(jù),這里是一個(gè)i32類型的數(shù)字
    let shared_number = Arc::new(Mutex::new(0));

    // 定義一個(gè)線程向量,用于存儲(chǔ)創(chuàng)建的線程
    let mut threads = Vec::new();

    // 創(chuàng)建10個(gè)線程,每個(gè)線程對(duì)共享數(shù)據(jù)進(jìn)行1000次遞增操作
    for _ in 0..10 {
        // 克隆Arc,使得每個(gè)線程都擁有一個(gè)指向共享數(shù)據(jù)的引用
        let num_clone = Arc::clone(&shared_number);
        let handle = thread::spawn(move || {
            // 嘗試獲取Mutex的鎖,這是一個(gè)阻塞操作,如果鎖不可用,線程會(huì)等待
            let mut num = num_clone.lock().unwrap();
            for _ in 0..1000 {
                *num += 1;
            }
        });
        threads.push(handle);
    }

    // 等待所有線程完成操作
    for handle in threads {
        handle.join().unwrap();
    }

    // 獲取最終的共享數(shù)據(jù)值并打印
    let final_num = shared_number.lock().unwrap();
    println!("最終10個(gè)線程的累加結(jié)果: {}", final_num);
}

在這個(gè)示例中:

  • 首先創(chuàng)建了一個(gè)Arc<Mutex<i32>>類型的共享數(shù)據(jù),Arc用于在多個(gè)線程間共享Mutex,Mutex用于保護(hù)內(nèi)部的i32數(shù)據(jù)。
  • 循環(huán)創(chuàng)建10個(gè)線程,每個(gè)線程都克隆了Arc并嘗試獲取Mutex的鎖。一旦獲取到鎖,線程就可以安全地對(duì)共享數(shù)據(jù)進(jìn)行遞增操作。
  • 主線程使用join方法等待所有子線程完成操作。
  • 最后,主線程獲取并打印共享數(shù)據(jù)的最終值。由于Mutex的保護(hù),多個(gè)線程對(duì)共享數(shù)據(jù)的操作不會(huì)產(chǎn)生數(shù)據(jù)競爭,保證了數(shù)據(jù)的一致性。

運(yùn)行結(jié)果:

10個(gè)線程,每個(gè)累加1000,所以最后結(jié)果是1000*10=10000。

4. 總結(jié)

從上面的例子可以看出,Rust的閉包捕獲規(guī)則最初可能感覺很嚴(yán)格,但它們?cè)诖_保內(nèi)存安全數(shù)據(jù)競爭自由方面至關(guān)重要。

總之,

如果需要在另一個(gè)線程中擁有數(shù)據(jù),考慮使用move;

如果需要跨線程共享數(shù)據(jù),考慮使用Arc;

如果需要跨線程共享和修改數(shù)據(jù),考慮使用Arc+Mutex;

到此這篇關(guān)于淺析Rust多線程中如何安全的使用變量的文章就介紹到這了,更多相關(guān)Rust多線程使用變量內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • RUST語言函數(shù)的定義與調(diào)用方法

    RUST語言函數(shù)的定義與調(diào)用方法

    定義一個(gè)RUST函數(shù)使用fn關(guān)鍵字,下面通過本文給大家介紹RUST語言函數(shù)的定義與調(diào)用方法,感興趣的朋友跟隨小編一起看看吧
    2024-04-04
  • 詳解Rust Substrate框架中的Runtime

    詳解Rust Substrate框架中的Runtime

    ubstrate是一個(gè)區(qū)塊鏈開發(fā)框架,它提供了一系列模塊化和可擴(kuò)展的組件,可以幫助開發(fā)人員快速構(gòu)建自定義區(qū)塊鏈。 Runtime是Substrate區(qū)塊鏈的核心部分,文中有詳細(xì)的代碼示例,需要的朋友可以參考下
    2023-05-05
  • 如何使用VSCode配置Rust開發(fā)環(huán)境(Rust新手教程)

    如何使用VSCode配置Rust開發(fā)環(huán)境(Rust新手教程)

    這篇文章主要介紹了如何使用VSCode配置Rust開發(fā)環(huán)境(Rust新手教程),本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-07-07
  • Rust-使用dotenvy加載和使用環(huán)境變量的過程詳解

    Rust-使用dotenvy加載和使用環(huán)境變量的過程詳解

    系統(tǒng)的開發(fā),測試和部署離不開環(huán)境變量,今天分享在Rust的系統(tǒng)開發(fā)中,使用dotenvy來讀取和使用環(huán)境變量,感興趣的朋友跟隨小編一起看看吧
    2023-11-11
  • 淺析Rust多線程中如何安全的使用變量

    淺析Rust多線程中如何安全的使用變量

    這篇文章主要為大家詳細(xì)介紹了Rust如何在線程的閉包中安全的使用變量,包括共享變量和修改變量,文中的示例代碼講解詳細(xì),有需要的小伙伴可以參考下
    2025-01-01
  • rust交叉編譯問題及報(bào)錯(cuò)解析

    rust交叉編譯問題及報(bào)錯(cuò)解析

    這篇文章主要為大家介紹了rust交叉編譯問題及報(bào)錯(cuò)解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • 如何使用Rust的向量存儲(chǔ)值列表

    如何使用Rust的向量存儲(chǔ)值列表

    本文介紹了在Rust中使用向量存儲(chǔ)值列表的方法,包括創(chuàng)建、更新、讀取、遍歷、存儲(chǔ)多種類型以及內(nèi)存釋放等方面,向量是Rust中常用且強(qiáng)大的集合類型,熟練掌握其用法有助于編寫高效且安全的代碼
    2025-02-02
  • Rust遍歷 BinaryHeap的示例代碼

    Rust遍歷 BinaryHeap的示例代碼

    Rust 的 BinaryHeap 結(jié)構(gòu)體實(shí)現(xiàn)了迭代器接口,因此你可以遍歷它,如果你想要遍歷 BinaryHeap 中的所有元素,你可以使用 .into_iter() 方法將其轉(zhuǎn)換為迭代器,并遍歷其中的元素,本文通過實(shí)例介紹Rust遍歷 BinaryHeap的相關(guān)知識(shí),感興趣的朋友一起看看吧
    2024-04-04
  • Rust中的內(nèi)部可變性與RefCell<T>詳解

    Rust中的內(nèi)部可變性與RefCell<T>詳解

    內(nèi)部可變性允許在不可變引用中修改內(nèi)部數(shù)據(jù),通過RefCell在運(yùn)行時(shí)檢查借用規(guī)則,適用于Mock對(duì)象和多所有權(quán)的可變性場景,結(jié)合Rc和RefCell實(shí)現(xiàn)多所有者共享并修改數(shù)據(jù),但僅適用于單線程
    2025-02-02
  • 深入講解下Rust模塊使用方式

    深入講解下Rust模塊使用方式

    很多時(shí)候,我們寫的代碼需要按模塊組織,因?yàn)槲覀儫o法將大量的代碼都寫在一個(gè)文件上,那樣不容易維護(hù),下面這篇文章主要給大家介紹了關(guān)于Rust模塊使用方式的相關(guān)資料,需要的朋友可以參考下
    2022-03-03

最新評(píng)論