Введение
Добро пожаловать в Extensible Concurrency With the Send and Sync Traits. Эта лабораторная работа является частью Rust Book. Вы можете практиковать свои навыки Rust в LabEx.
В этой лабораторной работе мы исследуем два концепции параллелизма в Rust - трейты Send и Sync, которые обеспечивают расширяемые возможности параллелизма за пределами стандартной библиотеки.
Extensible Concurrency with the Send and Sync Traits
Интересно, что в языке Rust очень мало функций параллелизма. Почти каждая функция параллелизма, которую мы обсуждали в этом разделе, является частью стандартной библиотеки, а не языка. Ваши возможности по обработке параллелизма не ограничиваются языком или стандартной библиотекой; вы можете написать собственные функции параллелизма или использовать те, которые написаны другими.
Однако, две концепции параллелизма встроены в язык: трейты std::marker Send и Sync.
Разрешение передачи владения между потоками с помощью Send
Маркерный типаж Send указывает на то, что владение значениями типа, реализующего Send, может быть передано между потоками. Почти каждый тип Rust является Send, но есть некоторые исключения, включая Rc<T>: он не может быть Send, потому что если вы клонируете значение Rc<T> и попытаетесь передать владение клоном другому потоку, оба потока могут обновить счетчик ссылок одновременно. По этой причине Rc<T> реализован для использования в однопоточных ситуациях, где вы не хотите платить штраф за производительность, связанный с потокобезопасностью.
Следовательно, система типов Rust и ограничения типажей гарантируют, что вы никогда случайно не отправите небезопасно значение Rc<T> между потоками. Когда мы попытались сделать это в Листинге 16-14, мы получили ошибку the trait Send is not implemented for Rc<Mutex<i32>> (типаж Send не реализован для Rc<Mutex>). Когда мы переключились на Arc<T>, который является Send, код скомпилировался.
Любой тип, полностью состоящий из типов Send, автоматически помечается как Send. Почти все примитивные типы являются Send, за исключением сырых указателей (raw pointers), которые мы обсудим в главе 19.
Allowing Access from Multiple Threads with Sync
Маркерный трейт Sync указывает, что безопасно использовать тип, реализующий Sync, из нескольких потоков. Другими словами, любой тип T является Sync, если &T (неизменяемая ссылка на T) является Send, что означает, что ссылка может быть безопасно передана в другой поток. Подобно Send, примитивные типы являются Sync, а типы, состоящие полностью из типов, которые являются Sync, также являются Sync.
Умный указатель Rc<T> также не является Sync по тем же причинам, по которым он не является Send. Тип RefCell<T> (о котором мы говорили в главе 15) и семейство связанных типов Cell<T> не являются Sync. Реализация проверки взятия в долг, которую RefCell<T> делает во время выполнения, не является потоко-безопасной. Умный указатель Mutex<T> является Sync и может быть использован для совместного доступа из нескольких потоков, как вы видели в разделе "Sharing a Mutex<T> Between Multiple Threads".
Implementing Send and Sync Manually Is Unsafe
Поскольку типы, состоящие из трейтов Send и Sync, автоматически также являются Send и Sync, мы не должны реализовывать эти трейты вручную. Как маркерные трейты, у них даже нет методов для реализации. Они просто полезны для обеспечения инвариантов, связанных с параллелизмом.
Вручную реализация этих трейтов включает в себя реализацию небезопасного кода на Rust. Мы поговорим о использовании небезопасного кода на Rust в главе 19; на данный момент важной информацией является то, что создание новых параллельных типов, не состоящих из частей Send и Sync, требует тщательного мышления для поддержания гарантий безопасности. В https://doc.rust-lang.org/stable/nomicon в "The Rustonomicon" есть дополнительная информация о этих гарантиях и том, как их поддерживать.
Summary
Поздравляем! Вы завершили лабораторную работу Extensible Concurrency With the Send and Sync Traits. Вы можете практиковаться в других лабораторных работах в LabEx, чтобы улучшить свои навыки.