MST

星途 面试题库

面试题:Rust跨线程闭包与Send和Sync trait的深度关联

解释在Rust跨线程闭包调用场景下,`Send`和`Sync` trait的作用。假设有一个自定义结构体,包含一些成员变量,在跨线程闭包中使用这个结构体,需要满足什么条件才能保证线程安全?请通过代码示例说明如何实现,以及违反这些条件会导致什么问题。
47.4万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试
  1. SendSync trait 的作用

    • Send trait:表示实现该 trait 的类型的值可以安全地跨线程发送。如果一个类型 T 实现了 Send,意味着可以将 T 类型的值从一个线程转移到另一个线程。大部分 Rust 的基本类型(如 i32String 等)都实现了 Send
    • Sync trait:表示实现该 trait 的类型的值可以安全地在多个线程间共享。如果一个类型 T 实现了 Sync,意味着可以创建 &T 类型的引用并在多个线程间共享,因为共享引用要求被引用的数据是线程安全的。大部分 Rust 的基本类型也都实现了 Sync
  2. 自定义结构体在跨线程闭包中使用的条件

    • 结构体的所有成员变量都必须实现 Send,这样结构体本身才能实现 Send,从而可以跨线程发送。
    • 如果需要在多个线程间共享结构体的引用(例如通过 Arc),结构体的所有成员变量都必须实现 Sync,这样结构体本身才能实现 Sync
  3. 代码示例

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

// 定义一个自定义结构体
struct MyStruct {
    data: i32,
}

// MyStruct 自动实现 Send 和 Sync,因为 i32 实现了 Send 和 Sync
impl Send for MyStruct {}
impl Sync for MyStruct {}

fn main() {
    let my_struct = Arc::new(Mutex::new(MyStruct { data: 42 }));
    let my_struct_clone = my_struct.clone();

    let handle = thread::spawn(move || {
        let mut my_struct = my_struct_clone.lock().unwrap();
        my_struct.data += 1;
    });

    handle.join().unwrap();

    let my_struct = my_struct.lock().unwrap();
    println!("Final data: {}", my_struct.data);
}
  1. 违反条件导致的问题
    • 违反 Send 条件: 假设我们有一个结构体包含一个非 Send 的类型,比如 RcRc 不能跨线程发送,因为它的引用计数不是线程安全的):
use std::rc::Rc;

struct BadStruct {
    data: Rc<i32>,
}

fn main() {
    let bad_struct = BadStruct { data: Rc::new(42) };
    // 下面这行会编译错误,因为 BadStruct 没有实现 Send
    thread::spawn(move || {
        println!("Data: {}", bad_struct.data);
    });
}

编译时会报错,提示 BadStruct 没有实现 Send trait。

  • 违反 Sync 条件: 假设我们有一个结构体包含一个非 Sync 的类型,比如 CellCell 不实现 Sync,因为它内部可变性不是线程安全的):
use std::cell::Cell;

struct AnotherBadStruct {
    data: Cell<i32>,
}

fn main() {
    let shared = Arc::new(AnotherBadStruct { data: Cell::new(42) });
    let shared_clone = shared.clone();
    // 下面这行会编译错误,因为 AnotherBadStruct 没有实现 Sync
    let handle = thread::spawn(move || {
        shared_clone.data.set(43);
    });

    handle.join().unwrap();
}

编译时会报错,提示 AnotherBadStruct 没有实现 Sync trait。如果强制编译通过,运行时可能会出现数据竞争等未定义行为。