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



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

由于我是初学者,代码可能看起来很糟糕。对等体还没有在任何地方使用,因为我也想把它传递给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!rn")?;
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()
}

它编译得很好,但handle_client函数中的let mut stream = Arc::try_unwrap(arc).unwrap();会死机。我做错了什么?它为什么恐慌?

为什么恐慌?

您正在Result::Err上调用unwrapErr来自于Arc上的try_unwrap故障。

我做错了什么?

打开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!rn")?;
let peer_addr = stream.peer_addr()?;
let mut reader = std::io::BufReader::new(stream);
let mut buf = String::new();
// ... 
}
}

它在文档中说

如果Arc正好有一个强参考

否则,返回的Err与传入的Arc相同。

即使存在突出的弱引用,这也会成功。

(弱参考(

您的代码可以很好地处理一个强引用和多个弱引用。

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();
}

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

相关内容

  • 没有找到相关文章

最新更新