Создайте две изменяемые ссылки, которые являются потокобезопасными для структуры в Rust - PullRequest
0 голосов
/ 10 октября 2019

Я пытаюсь создать Async Reader и Writer в Tokio, они требуют отправки и должны быть поточно-ориентированными. (не похоже на способ написания однопоточного кода Tokio, который избегает мьютексов)

И читатель, и писатель должны взаимодействовать друг с другом, например, чтение данных может привести к ответу.

Мне бы хотелось, чтобы и Reader, и Writer имели потокобезопасный указатель на сеанс, который может обеспечить связь между ними.

/// 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 с целыми числами, а не изменяемые "объекты".

1 Ответ

2 голосов
/ 10 октября 2019

Давайте начнем с очистки нескольких вещей:

не похоже на способ написания однопоточного кода Tokio, который избегает мьютексов

Требование Mutexне имеет ничего общего с однопоточностью, но с изменчивыми заимствованиями. Всякий раз, когда вы порождаете будущее, это будущее является его собственной сущностью;он магически не является частью вашего struct, и большинство определенно не знает, как сохранить &mut self. В этом смысл Mutex - он позволяет вам динамически получать изменяемую ссылку на внутреннее состояние - а Arc позволяет вам иметь доступ к самому Mutex в нескольких местах.

ИхКстати, несинхронизированными эквивалентами являются Rc и Cell / RefCell, а их содержимое (синхронизированное или несинхронизированное) должно принадлежать типу.

Требование Send действительно отображаетсякогда вы используете futures поверх tokio, так как Executor требует, чтобы на нем появилось фьючерсы 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теперь есть собственная заимствованная (изменяемая и не изменяемая) ссылка на нашу сессию!

Фрагмент детской площадки выделяет сделанные изменения. Как я уже сказал, он работает сейчас, но он укусит вас в задницу в тот момент, когда вы попытаетесь что-то сделать, поскольку вам понадобится что-то поверх обоих ReadHalf и WriteHalf, чтобы иметь возможность использовать их правильно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...