Rust 多執行緒基礎

2021-09-27 12:51:07 字數 3991 閱讀 9248

好久不寫部落格了, 忙裡偷閒寫一篇, 主要參考自 the rust programming language 

來說說 rust 中的多執行緒.

乙個磁碟上的可執行程式, 在作業系統中跑起來, 就變成了乙個程序,這個程序包含了該程式的各種**, 讓不同**同時跑, 就得到了多執行緒.

多執行緒能導致的問題有

通常的, 直接呼叫系統提供的執行緒 api 介面來實現執行緒的方式稱之為1

:1執行緒模型,也就是說, 乙個程式語言執行緒對應於乙個系統級別的執行緒.

許多程式語言會在這些 api 介面的基礎之上, 實現自己的執行緒模型. 這樣子的話,看執行緒就會有兩個側, 一側是程式語言級別的, 乙個是作業系統級別的,稱之為m:n執行緒模型, 也就是說程式語言中的 m 個執行緒實際上對應於作業系統中的 n 條執行緒.

m:n模型中, 程式語言提供的執行緒也稱之為綠色執行緒(green thread).

由於m:n模型中, 程式語言需要提供乙個尺寸比較大的執行時(runtime)來管理執行緒,rust 作為一種系統級程式語言, 標準庫裡面只實現了1

:1的執行緒模型實現,以使得 runtime 尺寸盡可能小. 不過不要擔心, 已經有 crate 實現了m:n執行緒模型.

好了, 上面瞎 bb 了半天, 怎麼在 rust 中建立新的執行緒呢?

rust 給我們提供了介面 thread::spawn 來建立執行緒, 看一下秒懂

use std::thread;

use std::time::duration;

fn main() from the spawned thread!", i);

thread::sleep(duration::from_millis(1));

}});

for i in 11..15 from the main thread!", i);

thread::sleep(duration::from_millis(1));

}}

這裡有幾個執行緒? 答 1 個的都是學渣.

主線程使用 thread::spawn 啟動了乙個子執行緒.

spawn 之後子執行緒就立馬啟動了, 然後**立即回到了主線程,子執行緒和主線程就開始雙兔傍地走, 一起走哦.

在我這裡一次輸出看起來是這樣子的

hi number 11 from the main thread!

hi number 1 from the spawned thread!

hi number 12 from the main thread!

hi number 2 from the spawned thread!

hi number 13 from the main thread!

hi number 3 from the spawned thread!

hi number 14 from the main thread!

hi number 4 from the spawned thread!

因為控制台 io 肯定是加鎖了的, 一次只能有乙個輸出,所以儘管子執行緒和主線程同時執行, 我們看到的還是子執行緒和主線程交替輸出.

我們突然發現子執行緒好像沒執行完就掛掉了, 只輸出了 1, 2, 3, 4 死在 5 上面,當然不是如來佛祖一巴掌拍死的, 而是主線程結束了, 所以子執行緒就涼涼了.

很好理解對不對. 可愛的你托起小臉蛋問, 那子執行緒怎麼才能不涼涼呢?

實際上 thread::spawn 的函式宣告是這樣子的

pub fn spawn(f: f) -> joinhandlewhere

f: fnonce() -> t,

f: send + 'static,

t: send + 'static,

哇, 這是什麼鬼東西, 看不懂. 看不懂沒關係, 返回值總能看到吧, 是乙個joinhandler, 當然了 joinhandler 又是個什麼鬼!

行了, 先不管那麼多, 不過就從名字來看, 差不多可以知道是執行緒的控制代碼(嗯, 事實就是這樣).

通過 joinhandler 的 join 方法我們可以阻塞宿主執行緒, 讓子執行緒執行完畢. 能不能說人話?

在上面這個例子中, 宿主執行緒就是主線程, 所以我們只需要在主線程中執行 join 方法,那麼宿主執行緒就會等待子執行緒執行完畢後, 才回自己再開始執行.

所以程式設計師只需要這麼悄悄該上那麼一筆, 如下所示

use std::thread;

use std::time::duration;

fn main() from the spawned thread!", i);

thread::sleep(duration::from_millis(1));

}});

handle.join().unwrap();

for i in 11..15 from the main thread!", i);

thread::sleep(duration::from_millis(1));

}}

然後就可以讓井然有序的執行起來, 輸出如下所示

hi number 1 from the spawned thread!

hi number 2 from the spawned thread!

hi number 3 from the spawned thread!

hi number 4 from the spawned thread!

hi number 5 from the spawned thread!

hi number 6 from the spawned thread!

hi number 7 from the spawned thread!

hi number 8 from the spawned thread!

hi number 9 from the spawned thread!

hi number 11 from the main thread!

hi number 12 from the main thread!

hi number 13 from the main thread!

hi number 14 from the main thread!

上一節中我們看到 spawn 的引數 f 是乙個 fnonce 的閉包型別,這種閉包型別通過 move 可以獲得, 也就是一次性獲取捕獲的物件的所有權.

怎麼用呢, 也是很容易啦

use std::thread;

fn main() ", v);

});handle.join().unwrap();

}

程式設計師說要有光, 上帝嘿嘿一笑關了燈. 於是黑暗來了, 編譯報錯

error[e0373]: closure may outlive the current function, but it borrows `v`, which is owned by the current function

--> main.rs:6:32

|6 | let handle = thread::spawn(|| ", v);

| - `v` is borrowed here

help: to force the closure to take ownership of `v` (and any other referenced variables), use the `move` keyword

|6 | let handle = thread::spawn(move || ", v);

});handle.join().unwrap();

}

上帝笑了笑, 說道: 生活就是這麼樸實無華且枯燥.

該洗洗睡了孩子.

Rust多執行緒下共享變數

但是,本文不涉及原理性介紹,請自行搜尋。執行緒安全的引用計數器,arc代表atomaticlly reference counted 原子引用計數。該型別arc提供t在堆中分配的type值的共享所有權。呼叫clone將arc產生乙個新arc例項,該例項指向堆上與源相同的分配arc,同時增加引用計數。...

多執行緒基礎

對於多執行緒程式設計,很多人概念不清,寫 的時候要麼是處處加鎖,影響效能不說,還容易莫名其妙的死鎖,還有人對多執行緒敬而遠之。所以學習多執行緒程式設計最重要的不是學習 api,而是理解什麼才是多執行緒安全的 從例子說起 include include long global1 0 volatile ...

多執行緒基礎

什麼是併發 同時執行多個程式,或者乙個程式的多段 在巨集觀上,存在併發的,但是在微觀上,其實不存在併發 時間片 在計算機中,使用時間片來實現併發的運算 在計算甲中,在最小的單位時間上 只能執行乙個運算 用來控制多個程式之間的輪轉,使得程式交替的執行 達到併發的目的 多個cpu 多個核心 才能實現真正...