问题:
我们涉及了一个socket连接的类,每次收到数据以后,我们都会把tokio::net::TcpStream对应的tcp_stream传递给其他线程。
起初设计如下:
pub struct TarNetStream {
stream:TcpStream, //1
...
}
pub trait TarListener {
fn on_event(&self,event:Event,data:Option<Vec<u8>>,stream:Arc<Box<TarNetStream>>); //2
}
1.stream直接move给TarNetStream
2.回调函数中采用了Arc智能指针
问题1:由于stream被move了,所以多线程编译会直接报错。
改进1:将成员变量变成Arc>(由于stream的read/write都需要mut权限,所以这里需要用refcell)
pub struct TarNetStream {
stream:Arc<RefCell<TcpStream>>,
}
问题2:正常都能使用,但是多线程调用的时候会提示Refcell不能再多线程中使用
改进2:添加mutex锁
pub struct TarNetStream {
stream:Arc<tokio::sync::Mutex<RefCell<TcpStream>>>,
}
问题3:运行直接卡死。原因如下:
线程1运行读:
let obj = stream.lock().await;
let result = obj.try_borrow_mut().unwrap().read(&mut buf).await;//1
线程2运行写:
let obj = stream.lock().await;//2
let result = obj.try_borrow_mut().unwrap().write(buf).await;
1.没有数据,这里卡死
2.由于线程1一直在等数据,所以线程2只能在这里2处卡住。
改进4:读写分离
pub struct TarNetStream<'a>'> {
//stream:Arc<RefCell<TcpStream>>,
read_stream:tokio::sync::Mutex<tokio::net::tcp::ReadHalf<'a'>>>,
write_stream:tokio::sync::Mutex<WriteHalf<'a'>>>,
...
}
问题4:异步线程调用时候编译提示生命周期有问题,应该是ReadHalf/WriteHalf里面存放的是stream的引用,多线程情况下会出现问题,所以直接编译报错?
改进4:移除生命周期,采用OwnerReadHalf/WriteHalf
pub struct TarNetStream {
//stream:Arc<RefCell<TcpStream>>,
read_stream:tokio::sync::Mutex<tokio::net::tcp::OwnedReadHalf>,
write_stream:tokio::sync::Mutex<OwnedWriteHalf>,
...
}
备考:
如果需要使用OwnedWriteHalf/OwnedReadHalf,需要类似如下的调用: