我正在尝试在tokio中创建异步Reader和Writer,这些需要Send,并且必须是线程安全的。 (似乎不是编写避免多文本的单线程tokio代码的方法)
读取器和写入器都需要交互,例如读取数据可能会导致响应。
我希望Reader和Writer都具有指向Session的线程安全指针,以确保两者之间的通信。
/// function on the
impl Session {
pub fn split(&mut self, sock: TcpStream) -> (Reader, Writer) {
let (read_half, write_half) = sock.split();
let session = Arc::new(RwLock::new(self)); // <- expected lifetime
( Reader::new(session, read_half), Writer::new(Arc::clone(session), write_half) )
}
...
}
pub struct Reader {
session: Arc<RwLock<&mut StompSession>>,
read_half: ReadHalf<TcpStream>,
...
pub struct Writer {
session: Arc<RwLock<&mut StompSession>>,
write_half: WriteHalf<TcpStream>,
....
我不太了解Arc<RwLock<&mut StompSession>>
和Arc<RwLock<StompSession>>
之间的区别,它们都只能谈论指针。
[通过自然地使用借阅检查器来解决这个问题,生锈的书只提供了带有整数而不是可变的“对象”的RRwLock的示例。
让我们先清除一些内容:
似乎不是编写避免互斥的单线程tokio代码的方法
Mutex
要求与单线程无关,但与可变借位无关。每当您产生一个未来时,那个未来就是它自己的实体。它不是struct
的魔术部分,大多数definitely不知道如何保存&mut self
。这就是Mutex
的意义-它允许您动态获取对内部状态的可变引用-并且Arc
允许您在多个位置访问Mutex
本身。
顺便说一下,[它们的非同步等效项是Rc
和Cell
/ RefCell
,并且它们的内容(无论是同步的还是未同步的)应该是拥有的类型。
Send
要求实际上是在futures
上方使用tokio
时显示的,因为Executor
要求在其上产生的期货为Executor
(出于明显的原因-您could Send
方法,但这会导致超出解决方案的更多问题)。
现在,回到您的问题。我将为您提供最短路径来解答您的问题。但是,这将不是完全正确的处理方式。但是,由于我不知道您要在spawn_local
之上使用什么协议或您有什么样的要求,因此我无法指出正确的方向(尚未)。因此,这里有评论-给我更多的要求,我会很乐意对此进行编辑!
反正回到问题。由于TcpStream
更适合用于自有类型,因此我们现在要这样做,并“修复”您的Mutex<_>
和Reader
:
Writer
由于我们已对此进行了更改,因此我们还需要在其他地方进行反映,但是要做到这一点,我们将需要消耗pub struct Reader {
session: Arc<RwLock<Session>>,
read_half: ReadHalf<TcpStream>,
}
pub struct Writer {
session: Arc<RwLock<StompSession>>,
write_half: WriteHalf<TcpStream>,
}
。很好,但是,由于我们将在两个对象中都有一个self
副本,因此我们返回:
Arc<Mutex<_>>
然后瞧瞧,它会编译,并且每个impl Session {
pub fn split(self, sock: TcpStream) -> (Reader, Writer) {
let (read_half, write_half) = sock.split();
let session = Arc::new(RwLock::new(self));
( Reader::new(session.clone(), read_half), Writer::new(session, write_half) )
}
}
/ Writer
对现在都有自己的可借用(可变和非可变)引用我们的会话!
Reader
高亮显示所做的更改。就像我说的那样,它现在可以工作,但是当您尝试做某事时,它会被您咬死,因为您需要在playground snippet和ReadHalf
上都需要一些东西才能正确使用它们。