<acronym id="s8ci2"><small id="s8ci2"></small></acronym>
<rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
<acronym id="s8ci2"></acronym>
<acronym id="s8ci2"><center id="s8ci2"></center></acronym>
0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Rust的多線程編程概念和使用方法

科技綠洲 ? 來源:TinyZ ? 作者:TinyZ ? 2023-09-20 11:15 ? 次閱讀

Rust是一種強類型、高性能的系統編程語言,其官方文檔中強調了Rust的標準庫具有良好的并發編程支持。Thread是Rust中的一種并發編程方式,本文將介紹Rust中thread的相關概念、方法和字段、常見用法以及多線程的一些實踐經驗。由淺入深帶你零基礎玩轉Rust的多線程編程。

線程的基本概念和使用方法

Thread是Rust中并發編程的一種基本方式。Rust中的Thread使用標準庫中的std::thread::Thread結構體表示。我們可以通過下面的代碼來創建一個Thread:

use std::thread;

fn main() {
    let handle = thread::spawn(|| {
        // 子線程執行的代碼
    });
}

其中的||表示閉包,該閉包中的代碼將在子線程中執行。調用thread::spawn方法會返回一個Result,該Result包含一個智能指針,該智能指針擁有對線程的所有權,如果線程執行成功則返回Ok,否則返回Err。通過這個智能指針我們可以管理線程的生命周期和操作線程。

當線程中的代碼執行完畢時,我們可以使用以下代碼將線程加入主線程:

handle.join().expect("執行失敗");

Thread也支持通過std::thread::Builder結構體進行創建,Builder提供了一些線程的配置項,如線程名字、線程優先級、棧大小等。

use std::thread;

fn main() {
    let builder = thread::Builder::new().name("my_thread".into());
    let handle = builder.spawn(|| {
        // 子線程執行的代碼
    });
}

線程的字段和方法

Thread結構體中提供了一些有用的字段和方法。

線程名稱

Rust中的Thread對象有一個名稱屬性,可以通過thread::current()函數獲取當前線程的名稱,也可以通過std::thread::Builder結構體設置線程的名稱。

use std::thread;

fn main() {
    let thr0 = thread::current();
    let thread_name = thr0.name().unwrap_or("unknown");
    println!("當前線程的名稱:{}", thread_name);
    
    let builder = thread::Builder::new().name("my_thread".into());
    let handle = builder.spawn(move || {
        let thr = thread::current();
        let name = thr.name().unwrap_or("unknown");
        println!("當前線程的名稱:{}", name);
    });
    handle.expect("執行失敗").join().unwrap();
}
//  輸出結果:
// 當前線程的名稱:main
// 當前線程的名稱:my_thread

線程id

Rust中的Thread對象還有一個id屬性,可以通過thread::current()函數獲取當前線程的id,也可以通過std::thread::Builder結構體設置線程的id。

use std::thread;

fn main() {
    let thread_id = thread::current().id();
    println!("當前線程的id:{:?}", thread_id);
    
    let builder = thread::Builder::new().name("my_thread".into());
    let handle = builder.spawn(|| {
        let id = thread::current().id();
        println!("當前線程的id:{:?}", id);
    });
    handle.expect("執行失敗").join().unwrap();
}
//  輸出結果:
// 當前線程的id:ThreadId(1)
// 當前線程的id:ThreadId(2)

線程休眠

Rust中Thread對象提供了一個sleep方法,用于讓線程休眠指定時間。

use std::{thread, time};

fn main() {
    println!("線程休眠前:{:?}", time::Instant::now());
    thread::sleep(time::Duration::from_secs(2));
    println!("線程休眠后:{:?}", time::Instant::now());
}
//  輸出結果:
// 線程休眠前:Instant { tv_sec: 9667960, tv_nsec: 471430161 }
// 線程休眠后:Instant { tv_sec: 9667962, tv_nsec: 471515229 }

線程狀態

Rust中Thread對象表示的是系統中的一個線程,可以通過thread::JoinHandle結構體的is_finalized()和thread::Thread的panicking()方法來查看線程是否結束和是否因panic而結束。

use std::thread;

fn main() {
    let handle = thread::spawn(|| {
        // TODO: 執行耗費時間的任務
    });
    while !handle.is_finished() {
        thread::sleep_ms(100);
    }
    if thread::panicking() {
        println!("線程因panic而結束");
    } else {
        println!("線程正常結束");
    }
}

常用用法和示例

單線程執行

我們可以使用Thread開啟一個單線程,并在該線程中執行我們的代碼。當該線程執行完畢后,我們通過JoinHandle.join()方法將該線程加入主線程。

use std::thread;

fn main() {
    let handle = thread::spawn(|| {
        println!("Hello Thread!");
    });
    
    handle.join().unwrap();
}

多線程執行

我們可以使用多個Thread對象并行地執行任務,實現多線程編程。

use std::thread;

fn main() {
    let handle1 = thread::spawn(|| {
        for i in 0..5 {
            println!("Thread1: {}", i);
        }
    });
    let handle2 = thread::spawn(|| {
        for i in 0..5 {
            println!("Thread2: {}", i);
        }
    });
    
    handle1.join().unwrap();
    handle2.join().unwrap();
}

線程間通信

Rust中線程間通信可以通過channel實現。在以下例子中,我們開啟兩個線程,一個線程向channel發送數據,另一個線程從channel接收數據。兩個線程可以通過channel實現數據共享和交換。

use std::thread;
use std::sync::mpsc;

fn main() {
    let (tx, rx) = mpsc::channel();
    let handle1 = thread::spawn(move || {
        tx.send("Hello Thread!".to_string()).unwrap();
    });
    let handle2 = thread::spawn(move || {
        let msg = rx.recv().unwrap();
        println!("{}", msg);
    });
    
    handle1.join().unwrap();
    handle2.join().unwrap();
}

進階用法:多線程協作和鎖

多線程協作

當線程之間需要協作執行任務時,我們可以通過Rust中提供的互斥鎖Mutex和讀寫鎖RwLock來實現。

以下是一個簡單的例子,在這個例子中我們開啟兩個線程,一個線程向共享變量加1,另一個線程向共享變量減1。由于有兩個線程同時修改共享變量,我們需要使用Mutex來進行加鎖和解鎖操作。

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

fn main() {
    let shared_count = Arc::new(Mutex::new(0));
    let thread1 = shared_count.clone();
    let handle1 = thread::spawn(move || {
        for _ in 0..10 {
            let mut count = thread1.lock().unwrap();
            *count += 1;
        }
    });
    let thread2 = shared_count.clone();
    let handle2 = thread::spawn(move || {
        for _ in 0..10 {
            let mut count = thread2.lock().unwrap();
            *count -= 1;
        }
    });
    
    handle1.join().unwrap();
    handle2.join().unwrap();
    println!("shared_count: {:?}", *shared_count.lock().unwrap());
}
//    輸出結果:
//  shared_count: 0

在多線程編程中,鎖是一種常見的同步機制,它用于保護共享數據不受到并發訪問的影響。Rust標準庫中提供了鎖的實現Mutex、RwLock、Barrier、Condvar等等。

Mutex

Mutex是Rust中最基本的鎖機制,它提供了互斥訪問的機制。當多個線程同時對一個共享資源進行訪問時,Mutex會對該資源進行加鎖,當一個線程訪問該資源時,其他線程無法訪問該資源,直到該線程解鎖該資源。

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

fn main() {
    let shared_data = Arc::new(Mutex::new(0));
    let thread1 = shared_data.clone();
    let handle1 = thread::spawn(move || {
        for _ in 0..10 {
            let mut data = thread1.lock().unwrap();
            *data += 1;
        }
    });
    let thread2 = shared_data.clone();
    let handle2 = thread::spawn(move || {
        for _ in 0..10 {
            let mut data = thread2.lock().unwrap();
            *data -= 1;
        }
    });
    
    handle1.join().unwrap();
    handle2.join().unwrap();
    println!("shared_data: {:?}", *shared_data.lock().unwrap());
}
//    輸出結果:
//  shared_data: 0

RwLock

RwLock是一種讀寫鎖,它提供了兩種訪問方式:讀取訪問和寫入訪問,當同時有多個讀操作時,RwLock會共享鎖,允許多個線程同時訪問該數據,當進行寫操作時,RwLock會對該數據進行排它鎖,只允許一個線程進行訪問。

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

fn main() {
    let shared_data = Arc::new(RwLock::new(0));
    let thread1 = shared_data.clone();
    let handle1 = thread::spawn(move || {
        for _ in 0..10 {
            let mut data = thread1.write().unwrap();
            *data += 1;
        }
    });
    let thread2 = shared_data.clone();
    let handle2 = thread::spawn(move || {
        for _ in 0..10 {
            let data = thread2.read().unwrap();
            println!("data: {:?}", *data);
        }
    });
    
    handle1.join().unwrap();
    handle2.join().unwrap();
    println!("shared_data: {:?}", *shared_data.read().unwrap());
}
//    輸出結果:
// data: 10
// data: 10
// data: 10
// data: 10
// data: 10
// data: 10
// data: 10
// data: 10
// data: 10
// data: 10
// shared_data: 10

RwLock還提供了一個try_read()方法,可以進行非阻塞式的讀操作。

Barrier

Barrier是一種同步機制,它提供了一個點,當多個線程只有在該點處到達才能繼續執行。Barrier有一個計數器,當計數器到達值N時,所有在該Barrier處等待的線程可以繼續執行。

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

fn main() {
    let barrier = Arc::new(Barrier::new(3));
    let thread1 = barrier.clone();
    let handle1 = thread::spawn(move || {
        println!("Thread1 step1.");
        thread1.wait();
        println!("Thread1 step2.");
    });
    let thread2 = barrier.clone();
    let handle2 = thread::spawn(move || {
        println!("Thread2 step1.");
        thread2.wait();
        println!("Thread2 step2.");
    });
    
    handle1.join().unwrap();
    handle2.join().unwrap();
}
//    輸出結果:
// Thread1 step1.
// Thread2 step1.
// ERROR Timeout

最佳實踐:安全地使用Thread

在使用Thread進行多線程編程時,為了保證線程安全,我們需要注意以下幾點:

  • ? 在多線程程序中避免使用靜態變量,單例模式和全局變量,這些變量可能被多個線程同時訪問。
  • ? 在多線程編程中,一定要避免使用裸指針和內存共享,這種方式可能導致數據競爭和未定義行為。
  • ? 使用Rust的鎖機制Mutex和RwLock等,保證共享數據的線程安全性。
  • ? 編寫多線程程序時,應該考慮線程池的設計,防止創建過多的線程帶來的資源錯亂和性能損失。
  • ? 多線程程序的并發度一定要注意控制,過高的并發度反而會導致性能下降。

以上都是在使用Thread時應該注意的一些安全問題,遵循這些原則可以提高多線程程序的可維護性和安全性。

總結

本章節通過代碼示例深入的探討了Rust中thread的線程的基本概念,線程的字段和方法,常用用法和示例,多線程協作和鎖以及thread最佳實踐經驗。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 代碼
    +關注

    關注

    30

    文章

    4588

    瀏覽量

    67222
  • 多線程編程
    +關注

    關注

    0

    文章

    15

    瀏覽量

    6667
  • Thread
    +關注

    關注

    2

    文章

    83

    瀏覽量

    25736
  • Rust
    +關注

    關注

    1

    文章

    225

    瀏覽量

    6434
收藏 人收藏

    評論

    相關推薦

    labview多線程編程

    子曰:何為labview多線程編程?
    發表于 03-11 15:46

    Python多線程編程原理

    多線程使用方法Python中使用線程有兩種方式,分別是函數或者用類來包裝線程對象。用函數來包裝線程對象的方式用函數來包裝
    發表于 11-22 14:01

    多線程解決思路一

    使用方法節點實現多線程,兩個線程之間的數據傳輸也都使用方法節點的方式實現。1、初始化時打開另一個線程。2、程序運行過程中實現對被調
    發表于 07-06 17:21

    嵌入式Linux多線程編程

    嵌入式Linux多線程編程-學習資源-華清遠見清遠見嵌入式學院:清遠見嵌入式學院:《嵌入式應用程序設計》——第5 章 嵌入式Linux 多線程編程第5 章 嵌入式Linux
    發表于 11-05 06:54

    QNX環境下多線程編程

    介紹了QNX 實時操作系統和多線程編程技術,包括線程間同步的方法、多線程程序的分析步驟、線程基本
    發表于 08-12 17:37 ?30次下載

    linux多線程編程課件

    電子發燒友為您提供了linux多線程編程課件,希望對您學習 linux 有所幫助。部分內容如下: *1、多線程模型在單處理器模型和多處理器系統上,都能改善響應時間和吞吐量。 *2、線程
    發表于 07-10 11:58 ?0次下載

    linux多線程編程開發

    本文中我們針對 Linux 上多線程編程的主要特性總結出 5 條經驗,用以改善 Linux 多線程編程的習慣和避免其中的開發陷阱。在本文中,我們穿插一些 Windows 的
    發表于 12-26 14:24 ?55次下載
    linux<b class='flag-5'>多線程</b><b class='flag-5'>編程</b>開發

    MFC下的多線程編程

    計算機上的上位機制作工具語言之MFC下的多線程編程
    發表于 09-01 14:55 ?0次下載

    VC-MFC多線程編程詳解

    VC編程中關于 MFC多線程編程的詳解文檔
    發表于 09-01 15:01 ?0次下載

    Windows多線程編程

    計算機上的上位機制作工具語言之Windows多線程編程,感興趣的可以看看。
    發表于 09-01 15:27 ?0次下載

    關于多線程編程教程及經典應用案例的匯總分析

    在一個程序中,這些獨立運行的程序片段叫作線程,利用它編程概念就叫作多線程處理。具有多線程能力的計算機因有硬件支持而能夠在同一時間執行多于一
    發表于 10-16 16:46 ?0次下載

    linux多線程編程技術

    1 引言 線程(thread)技術早在60年代就被提出,但真正應用多線程到操作系統中去,是在80年代中期,solaris是這方面的佼佼者。傳統的 Unix也支持線程概念,但是在一個進
    發表于 10-24 16:01 ?5次下載

    什么是多線程編程?多線程編程基礎知識

    摘要:多線程編程是現代軟件技術中很重要的一個環節。要弄懂多線程,這就要牽涉到多進程。本文主要以多線程編程以及
    發表于 12-08 16:30 ?1.2w次閱讀

    多線程如何保證數據的同步

    多線程編程是一種并發編程方法,意味著程序中同時運行多個線程,每個線程可獨立執行不同的任務,共享
    的頭像 發表于 11-17 14:22 ?447次閱讀

    mfc多線程編程實例

    (圖形用戶界面)應用程序的開發。在這篇文章中,我們將重點介紹MFC中的多線程編程。 多線程編程在軟件開發中非常重要,它可以實現程序的并發執行,提高程序的效率和響應速度。MFC提供了豐富
    的頭像 發表于 12-01 14:29 ?658次閱讀
    亚洲欧美日韩精品久久_久久精品AⅤ无码中文_日本中文字幕有码在线播放_亚洲视频高清不卡在线观看
    <acronym id="s8ci2"><small id="s8ci2"></small></acronym>
    <rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
    <acronym id="s8ci2"></acronym>
    <acronym id="s8ci2"><center id="s8ci2"></center></acronym>