为什么 Arc::try_unwrap() 会引起恐慌?

Why does Arc::try_unwrap() cause a panic?

我正在编写一个简单的聊天服务器,它向所有连接的客户端广播消息。

代码可能看起来很糟糕,因为我是初学者。 Peers 还没有在任何地方使用,因为我也想将它传递给 handle_client 函数,所以当数据在流中可用并成功读取时,我想在所有连接的客户端上广播它。我知道这不是一个好方法,我只是想了解一般情况下如何做这样的事情。

use std::io::BufRead;
use std::io::Write;
use std::net::{TcpListener, TcpStream};
use std::sync::Arc;

fn handle_client(arc: Arc<TcpStream>) -> std::io::Result<()> {
    let mut stream = Arc::try_unwrap(arc).unwrap();

    stream.write(b"Welcome to the server!\r\n")?;
    println!("incomming connection: {:?}", stream);

    std::thread::spawn(move || -> std::io::Result<()> {
        let peer_addr = stream.peer_addr()?;
        let mut reader = std::io::BufReader::new(stream);
        let mut buf = String::new();

        loop {
            let bytes_read = reader.read_line(&mut buf)?;
            if bytes_read == 0 {
                println!("client disconnected {}", peer_addr);
                return Ok(());
            }

            buf.remove(bytes_read - 1);
            println!("{}: {}", peer_addr, buf);

            buf.clear();
        }
    });

    Ok(())
}

fn start() -> std::io::Result<()> {
    let listener = TcpListener::bind("0.0.0.0:1111")?;
    println!("listening on {}", listener.local_addr()?.port());

    let mut peers: Vec<Arc<TcpStream>> = vec![];

    for stream in listener.incoming() {
        let mut stream = stream.unwrap();
        let arc = Arc::new(stream);

        peers.push(arc.clone());
        handle_client(arc.clone()).unwrap();
    }

    Ok(())
}

fn main() -> std::io::Result<()> {
    start()
}

它编译正常,但 let mut stream = Arc::try_unwrap(arc).unwrap();handle_client 函数中出现混乱。我究竟做错了什么?为什么会恐慌?

Why is it panicking?

您正在 Result::Err 上呼叫 unwrapErr 来自 try_unwrapArc 上失败。

What am I doing wrong?

展开 Arc 移动 它的价值并获得它的所有权。这失败了,因为存在相同 Arc 的三个克隆:

  • 主循环中的一个仍在范围内
  • peers向量中的一个
  • 您要在 handle_client.
  • 中解包的那个

如果 Rust 允许您解包并移动值,那么其他两个克隆将变得无效。 您可以使用 ArcDeref 实现来借用它,而不是展开值:

let stream: &TcpStream = &arc;

由于你现在是从Arc中借用值,你需要将arc变量的作用域移动到新线程中,否则借用检查器将无法确保它与线程一样长:

fn handle_client(arc: Arc<TcpStream>) -> std::io::Result<()> {
    std::thread::spawn(move || -> std::io::Result<()> {
        let mut stream: &TcpStream = &arc;
        stream.write(b"Welcome to the server!\r\n")?;

        let peer_addr = stream.peer_addr()?;
        let mut reader = std::io::BufReader::new(stream);
        let mut buf = String::new();

        // ... 
     }
}

the documentation

中说

Returns the contained value, if the Arc has exactly one strong reference.

Otherwise, an Err is returned with the same Arc that was passed in.

This will succeed even if there are outstanding weak references.

(weak reference)

您的代码可以在一个强引用和多个弱引用的情况下正常工作。

let mut peers: Vec<Weak<TcpStream>> = vec![];

for stream in listener.incoming() {
    let mut stream = stream.unwrap();
    let arc = Arc::new(stream);
    peers.push(Arc::downgrade(&arc));
    handle_client(arc).unwrap();
}

关于弱引用需要注意的一件事:如果你打开你的一个强引用,你将无法使用弱引用。