亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

詳解Rust編程中的共享狀態(tài)并發(fā)執(zhí)行

 更新時(shí)間:2023年11月15日 10:40:41   作者:二進(jìn)制空間安全  
雖然消息傳遞是一個(gè)很好的處理并發(fā)的方式,但并不是唯一一個(gè),另一種方式是讓多個(gè)線程擁有相同的共享數(shù)據(jù),本文給大家介紹Rust編程中的共享狀態(tài)并發(fā)執(zhí)行,感興趣的朋友一起看看吧

1.共享狀態(tài)并發(fā)

雖然消息傳遞是一個(gè)很好的處理并發(fā)的方式,但并不是唯一一個(gè)。另一種方式是讓多個(gè)線程擁有相同的共享數(shù)據(jù)。在學(xué)習(xí)Go語言編程過程中大家應(yīng)該聽到過一句口號(hào):"不要通過共享內(nèi)存來通訊"。

在某種程度上,任何編程語言中的信道都類似于單所有權(quán),因?yàn)橐坏⒁粋€(gè)值傳送到信道中,將無法再使用這個(gè)值。共享內(nèi)存類似于多所有權(quán):多個(gè)線程可以同時(shí)訪問相同的內(nèi)存位置。第十五章介紹了智能指針如何使得多所有權(quán)成為可能,然而這會(huì)增加額外的復(fù)雜性,因?yàn)樾枰阅撤N方式管理這些不同的所有者。Rust 的類型系統(tǒng)和所有權(quán)規(guī)則極大的協(xié)助了正確地管理這些所有權(quán)。作為一個(gè)例子,讓我們看看互斥器,一個(gè)更為常見的共享內(nèi)存并發(fā)原語。

互斥器(mutex)是 mutual exclusion 的縮寫,也就是說,任意時(shí)刻,其只允許一個(gè)線程訪問某些數(shù)據(jù)。為了訪問互斥器中的數(shù)據(jù),線程首先需要通過獲取互斥器的 (lock)來表明其希望訪問數(shù)據(jù)。鎖是一個(gè)作為互斥器一部分的數(shù)據(jù)結(jié)構(gòu),它記錄誰有數(shù)據(jù)的排他訪問權(quán)。因此,我們描述互斥器為通過鎖系統(tǒng) 保護(hù)(guarding)其數(shù)據(jù)。

互斥器以難以使用著稱,因?yàn)槟悴坏貌挥涀。?/p>

  • 在使用數(shù)據(jù)之前嘗試獲取鎖。
  • 處理完被互斥器所保護(hù)的數(shù)據(jù)之后,必須解鎖數(shù)據(jù),這樣其他線程才能夠獲取鎖。

作為一個(gè)現(xiàn)實(shí)中互斥器的例子,想象一下在某個(gè)會(huì)議的一次小組座談會(huì)中,只有一個(gè)麥克風(fēng)。如果一位成員要發(fā)言,他必須請求或表示希望使用麥克風(fēng)。一旦得到了麥克風(fēng),他可以暢所欲言,然后將麥克風(fēng)交給下一位希望講話的成員。如果一位成員結(jié)束發(fā)言后忘記將麥克風(fēng)交還,其他人將無法發(fā)言。如果對共享麥克風(fēng)的管理出現(xiàn)了問題,座談會(huì)將無法如期進(jìn)行!

正確的管理互斥器異常復(fù)雜,這也是許多人之所以熱衷于信道的原因。然而,在 Rust 中,得益于類型系統(tǒng)和所有權(quán),我們不會(huì)在鎖和解鎖上出錯(cuò)。

2.Mutex<T>的API

作為展示如何使用互斥器的例子,讓我們從在單線程上下文使用互斥器開始, 看下面的代碼:

use std::sync::Mutex;
fn main() {
    let m = Mutex::new(5);
    {
        let mut num = m.lock().unwrap();
        *num = 6;
    }
    println!("m = {:?}", m);
}

像很多類型一樣,我們使用關(guān)聯(lián)函數(shù) new 來創(chuàng)建一個(gè) Mutex<T>。使用 lock 方法獲取鎖,以訪問互斥器中的數(shù)據(jù)。這個(gè)調(diào)用會(huì)阻塞當(dāng)前線程,直到我們擁有鎖為止。

如果另一個(gè)線程擁有鎖,并且那個(gè)線程 panic 了,則 lock 調(diào)用會(huì)失敗。在這種情況下,沒人能夠再獲取鎖,所以這里選擇 unwrap 并在遇到這種情況時(shí)使線程 panic。

一旦獲取了鎖,就可以將返回值(在這里是num)視為一個(gè)其內(nèi)部數(shù)據(jù)的可變引用了。類型系統(tǒng)確保了我們在使用 m 中的值之前獲取鎖。m 的類型是 Mutex<i32> 而不是 i32,所以 必須 獲取鎖才能使用這個(gè) i32 值。我們是不會(huì)忘記這么做的,因?yàn)榉粗愋拖到y(tǒng)不允許訪問內(nèi)部的 i32 值。

Mutex<T> 是一個(gè)智能指針。更準(zhǔn)確的說,lock 調(diào)用 返回 一個(gè)叫做 MutexGuard 的智能指針。這個(gè)智能指針實(shí)現(xiàn)了 Deref 來指向其內(nèi)部數(shù)據(jù);其也提供了一個(gè) Drop 實(shí)現(xiàn)當(dāng) MutexGuard 離開作用域時(shí)自動(dòng)釋放鎖,為此,我們不會(huì)忘記釋放鎖并阻塞互斥器為其它線程所用的風(fēng)險(xiǎn),因?yàn)殒i的釋放是自動(dòng)發(fā)生的。

丟棄了鎖之后,可以打印出互斥器的值,并發(fā)現(xiàn)能夠?qū)⑵鋬?nèi)部的 i32 改為 6。

3.在線程間共享Mutex<T>

現(xiàn)在讓我們嘗試使用 Mutex<T> 在多個(gè)線程間共享值。我們將啟動(dòng)十個(gè)線程,并在各個(gè)線程中對同一個(gè)計(jì)數(shù)器值加一,這樣計(jì)數(shù)器將從 0 變?yōu)?10??聪旅娴拇a:

use std::sync::Mutex;
use std::thread;
fn main() {
    let counter = Mutex::new(0);
    let mut handles = vec![];
    for _ in 0..10 {
        let handle = thread::spawn(move || {
            let mut num = counter.lock().unwrap();
            *num += 1;
        });
        handles.push(handle);
    }
    for handle in handles {
        handle.join().unwrap();
    }
    println!("Result: {}", *counter.lock().unwrap());
}

這里創(chuàng)建了一個(gè) counter 變量來存放內(nèi)含 i32Mutex<T>, 接下來遍歷 range 創(chuàng)建了 10 個(gè)線程。使用了 thread::spawn 并對所有線程使用了相同的閉包:它們每一個(gè)都將調(diào)用 lock 方法來獲取 Mutex<T> 上的鎖,接著將互斥器中的值加一。當(dāng)一個(gè)線程結(jié)束執(zhí)行,num 會(huì)離開閉包作用域并釋放鎖,這樣另一個(gè)線程就可以獲取它了。

在主線程中,我們收集了所有的 join 句柄, 調(diào)用它們的 join 方法來確保所有線程都會(huì)結(jié)束。這時(shí),主線程會(huì)獲取鎖并打印出程序的結(jié)果。

編譯上面的代碼, Rust編譯器報(bào)了一個(gè)錯(cuò)誤:

錯(cuò)誤信息表明 counter 值在上一次循環(huán)中被移動(dòng)了。所以 Rust 告訴我們不能將 counter 鎖的所有權(quán)移動(dòng)到多個(gè)線程中。下面來看看如何修復(fù)這個(gè)錯(cuò)誤。

4.多線程和多所有權(quán)

我們先嘗試將Mutex<T>封裝進(jìn)Rc<T>中并在將所有權(quán)移入線程之前克隆Rc<T>,看下面代碼:

use std::rc::Rc;
use std::sync::Mutex;
use std::thread;
fn main() {
    let counter = Rc::new(Mutex::new(0));
    let mut handles = vec![];
    for _ in 0..10 {
        let counter = Rc::clone(&counter);
        let handle = thread::spawn(move || {
            let mut num = counter.lock().unwrap();
            *num += 1;
        });
        handles.push(handle);
    }
    for handle in handles {
        handle.join().unwrap();
    }
    println!("Result: {}", *counter.lock().unwrap());
}

再一次編譯代碼,納尼, 居然又報(bào)了另一個(gè)錯(cuò)誤, 成年人的崩潰誰能懂:

Rc<Mutex<i32>>` cannot be sent between threads safely`。這個(gè)錯(cuò)誤編譯器告訴我們原因是:`the trait `Send` is not implemented for `Rc<Mutex<i32>>。

Rc<T> 并不能安全的在線程間共享。當(dāng) Rc<T> 管理引用計(jì)數(shù)時(shí),它必須在每一個(gè) clone 調(diào)用時(shí)增加計(jì)數(shù),并在每一個(gè)克隆被丟棄時(shí)減少計(jì)數(shù)。Rc<T> 并沒有使用任何并發(fā)原語,來確保改變計(jì)數(shù)的操作不會(huì)被其他線程打斷。在計(jì)數(shù)出錯(cuò)時(shí)可能會(huì)導(dǎo)致詭異的 bug,比如可能會(huì)造成內(nèi)存泄漏,或在使用結(jié)束之前就丟棄一個(gè)值。我們所需要的是一個(gè)完全類似 Rc<T>,又以一種線程安全的方式改變引用計(jì)數(shù)的類型。

5.原子引用計(jì)數(shù)Arc<T>

在Rust標(biāo)準(zhǔn)庫中, 提供了一個(gè)名為Arc<T>的類型, 這是一個(gè)可以安全的用于并發(fā)環(huán)境的類型, 字母 “a” 代表 原子性(atomic),所以這是一個(gè) 原子引用計(jì)數(shù)(atomically reference counted)類型, 將代碼修改為:

use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
    let counter = Arc::new(Mutex::new(0));
    let mut handles = vec![];
    for _ in 0..10 {
        let counter = Arc::clone(&counter);
        let handle = thread::spawn(move || {
            let mut num = counter.lock().unwrap();
            *num += 1;
        });
        handles.push(handle);
    }
    for handle in handles {
        handle.join().unwrap();
    }
    println!("Result: {}", *counter.lock().unwrap());
}

再次編譯代碼, 執(zhí)行結(jié)果如下:

這次終于得到結(jié)果10, 程序從0數(shù)到10, 雖然過程看上去并不明顯, 但我們卻學(xué)到了很多關(guān)于Mutex<T>和線程安全的內(nèi)容。

到此這篇關(guān)于Rust編程中的共享狀態(tài)并發(fā)執(zhí)行的文章就介紹到這了,更多相關(guān)Rust共享狀態(tài)并發(fā)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • rust聲明式宏的實(shí)現(xiàn)

    rust聲明式宏的實(shí)現(xiàn)

    聲明式宏使得你能夠?qū)懗鲱愃?match?表達(dá)式的東西,來操作你所提供的?Rust代碼,它使用你提供的代碼來生成用于替換宏調(diào)用的代碼,感興趣的可以了解一下
    2023-12-12
  • rust 一個(gè)日志緩存記錄的通用實(shí)現(xiàn)方法

    rust 一個(gè)日志緩存記錄的通用實(shí)現(xiàn)方法

    本文給出了一個(gè)通用的設(shè)計(jì)模式,通過建造者模式實(shí)例化記錄對象,可自定義格式化器將實(shí)例化后的記錄對象寫入到指定的緩存對象中,這篇文章主要介紹了rust 一個(gè)日志緩存記錄的通用實(shí)現(xiàn)方法,需要的朋友可以參考下
    2024-04-04
  • rust中async/await的使用示例詳解

    rust中async/await的使用示例詳解

    在Rust中,async/await用于編寫異步代碼,使得異步操作更易于理解和編寫,通過使用await,在async函數(shù)或代碼塊中等待Future完成,而不會(huì)阻塞線程,允許同時(shí)執(zhí)行其他Future,這種機(jī)制簡化了異步編程的復(fù)雜性,使代碼更加直觀
    2024-10-10
  • rust文件讀寫的實(shí)現(xiàn)示例

    rust文件讀寫的實(shí)現(xiàn)示例

    Rust語言提供了強(qiáng)大的文件讀寫庫,使得開發(fā)者可以更加方便地進(jìn)行文件操作,并且其安全性可以有效避免文件操作中可能出現(xiàn)的風(fēng)險(xiǎn),本文就來詳細(xì)的介紹了rust文件讀寫的實(shí)現(xiàn)示例,感興趣的可以了解一下
    2023-12-12
  • 利用Rust實(shí)現(xiàn)一個(gè)簡單的Ping應(yīng)用

    利用Rust實(shí)現(xiàn)一個(gè)簡單的Ping應(yīng)用

    這兩年Rust火的一塌糊涂,甚至都燒到了前端,再不學(xué)習(xí)怕是要落伍了。最近翻了翻文檔,寫了個(gè)簡單的Ping應(yīng)用練練手,感興趣的小伙伴可以了解一下
    2022-12-12
  • Rust包和Crate超詳細(xì)講解

    Rust包和Crate超詳細(xì)講解

    這篇文章主要介紹了Rust包管理和Crate,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2022-12-12
  • Rust 能夠取代 C 語言嗎

    Rust 能夠取代 C 語言嗎

    Rust 是 Mozilla 基金會(huì)的一個(gè)雄心勃勃的項(xiàng)目,號(hào)稱是 C 語言和 C++ 的繼任者,這篇文章主要介紹了Rust 能夠取代 C 語言嗎的相關(guān)知識(shí),需要的朋友可以參考下
    2020-06-06
  • Rust中字符串類型&str和String的使用

    Rust中字符串類型&str和String的使用

    在Rust中,字符串是一種非常重要的數(shù)據(jù)類型,&str和String是Rust中兩種主要的字符串類型,本文主要介紹了Rust中字符串類型&str和String的使用,感興趣的可以了解一下
    2024-03-03
  • Rust利用tauri制作個(gè)效率小工具

    Rust利用tauri制作個(gè)效率小工具

    日常使用電腦中經(jīng)常會(huì)用到一個(gè)quicke工具中的輪盤菜單工具。但quicke免費(fèi)版很多功能不支持,且它的觸發(fā)邏輯用的不舒服,經(jīng)常誤觸。所以本文就來用tauri自制一個(gè)小工具,希望對大家有所幫助
    2023-02-02
  • rust流程控制的具體使用

    rust流程控制的具體使用

    在Rust中,控制流包括條件語句、循環(huán)和匹配模式等,用于實(shí)現(xiàn)程序的邏輯和流程控制,本文就來詳細(xì)的介紹一下,感興趣的可以了解一下
    2023-12-12

最新評論