MST

星途 面试题库

面试题:Rust OnceCell在复杂并发场景下的应用

假设你正在开发一个多线程的网络服务器,需要在多个线程间共享一个全局的连接池,使用OnceCell来初始化连接池。请描述实现过程中可能遇到的并发问题及如何解决,同时给出关键代码示例。
48.7万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试

可能遇到的并发问题

  1. 重复初始化:在多线程环境下,多个线程可能同时尝试初始化连接池,导致连接池被重复初始化,浪费资源并可能造成数据不一致。

解决方案

使用 OnceCell 来确保连接池只被初始化一次。OnceCell 提供了 get_or_init 方法,该方法能在并发环境下安全地初始化值,保证只有一个线程会执行初始化逻辑,其他线程等待初始化完成并获取已初始化的值。

关键代码示例(以 Rust 语言为例)

use std::sync::{Arc, OnceCell};
use std::net::TcpListener;
use std::thread;

// 定义全局连接池
static CONNECTION_POOL: OnceCell<Arc<TcpListener>> = OnceCell::new();

fn get_connection_pool() -> Arc<TcpListener> {
    CONNECTION_POOL.get_or_init(|| {
        let listener = TcpListener::bind("127.0.0.1:8080").expect("Failed to bind");
        Arc::new(listener)
    })
}

fn main() {
    // 模拟多个线程
    let mut handles = vec![];
    for _ in 0..10 {
        let handle = thread::spawn(|| {
            let pool = get_connection_pool();
            println!("Thread got connection pool: {:?}", pool);
        });
        handles.push(handle);
    }

    for handle in handles {
        handle.join().unwrap();
    }
}

在上述代码中:

  1. 定义了一个 OnceCell 类型的静态变量 CONNECTION_POOL 来存储连接池。
  2. get_connection_pool 函数通过 get_or_init 方法来获取或初始化连接池。初始化逻辑中创建了一个 TcpListener 并包装成 Arc 类型。
  3. main 函数中模拟了多个线程,每个线程调用 get_connection_pool 函数获取连接池,确保连接池只被初始化一次。