You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Rust中控制两个不同线程的打印顺序?

多线程输入输出同步问题解决

我写了个小 Rust 程序,开了两个线程:sender 线程负责提示用户输入,receiver 线程接收输入内容并打印到标准输出。

预期运行效果

> hello
< hello

实际运行效果

> hello
> < hello

问题代码

use std::io;
use std::io::Write;
use std::thread;
use std::sync::mpsc;

fn main() {
    let mut threads = vec![];
    let (tx, rx) = mpsc::sync_channel(1);

    // Sender
    threads.push(thread::spawn(move || {
        loop {
            let mut input = String::new();

            print!("> ");
            io::stdout().flush().unwrap();
            io::stdin().read_line(&mut input).unwrap();
            tx.send(input).unwrap();
        }
    }));

    // Receiver
    threads.push(thread::spawn(move || {
        loop {
            let message = rx.recv().unwrap();
            println!("< {message}");
        }
    }));

    for thread in threads {
        thread.join().unwrap();
    }
}

我猜测是 receiver 执行println!("< {message}")时,sender 已经走到下一个print!("> "),导致两者输出被错误地混在一起刷新。


解决方案

问题核心是标准输出的操作没有线程同步,两个线程的输出操作并发执行,导致输出顺序混乱。解决思路是给标准输出加全局互斥锁,确保同一时间只有一个线程能操作 stdout。

修改后的代码

use std::io;
use std::io::Write;
use std::thread;
use std::sync::{mpsc, Mutex};
use std::sync::Arc;

fn main() {
    let mut threads = vec![];
    let (tx, rx) = mpsc::sync_channel(1);
    // 创建Arc包装的Mutex,实现跨线程共享的互斥访问
    let stdout_mutex = Arc::new(Mutex::new(io::stdout()));

    // Sender线程
    let sender_stdout = Arc::clone(&stdout_mutex);
    threads.push(thread::spawn(move || {
        loop {
            let mut input = String::new();

            // 获取锁后操作stdout
            let mut stdout = sender_stdout.lock().unwrap();
            print!("> ");
            stdout.flush().unwrap();
            // 立即释放锁,避免等待输入时占用锁资源
            drop(stdout);

            io::stdin().read_line(&mut input).unwrap();
            tx.send(input).unwrap();
        }
    }));

    // Receiver线程
    let receiver_stdout = Arc::clone(&stdout_mutex);
    threads.push(thread::spawn(move || {
        loop {
            let message = rx.recv().unwrap();
            // 获取锁后执行打印操作
            let mut stdout = receiver_stdout.lock().unwrap();
            writeln!(stdout, "< {}", message.trim_end()).unwrap();
        }
    }));

    for thread in threads {
        thread.join().unwrap();
    }
}

关键说明

  • 使用Arc<Mutex<io::Stdout>>实现跨线程的互斥访问:Arc用于多线程共享所有权,Mutex保证同一时间只有一个线程能操作 stdout。
  • Sender线程在打印提示符并刷新后,立即drop(stdout)释放锁,避免在等待用户输入的长时间里占用锁,影响Receiver的输出。
  • Receiver使用writeln!直接操作锁保护的stdout,同时用trim_end()去掉输入字符串末尾的换行符,避免输出出现多余空行。

修改后两个线程的输出操作会被串行化,就能得到预期的输出顺序。

内容的提问来源于stack exchange,提问作者Shlomo Gottlieb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 22:22:43