더 나은 동시성 이야기는 Rust 프로젝트의 주요 목표 중 하나이므로 목표 달성을 위해 프로젝트를 신뢰한다면 개선이 필요합니다. 완전 면책 조항 : 나는 Rust에 대해 높은 의견을 가지고 있으며 그것에 투자하고 있습니다. 요청에 따라 가치 판단을 피하고 (IMHO) 개선 보다는 차이점을 설명하려고 노력할 것 입니다.
안전하고 안전하지 않은 녹
"녹"은 두 가지 언어로 구성되어 있습니다. 하나는 시스템 프로그래밍의 위험으로부터 당신을 격리시키기 위해 열심히 노력하며, 그러한 열망이없는 더 강력한 언어입니다.
안전하지 않은 녹은 불쾌하고 잔인한 언어로 C ++과 매우 흡사합니다. 임의로 위험한 일을하고, 하드웨어와 대화하고, 메모리를 수동으로 관리하고, 발로 자신을 쏠 수 있습니다. 프로그램의 정확성이 궁극적으로 당신의 손에 있다는 점에서 C와 C ++와 매우 흡사합니다. 그와 관련된 다른 모든 프로그래머의 손. 키워드를 사용하여이 언어를 선택하면 unsafe
C 및 C ++에서와 같이 단일 위치에서 한 번의 실수만으로 전체 프로젝트가 중단 될 수 있습니다.
Safe Rust는 "기본"이며, 대부분의 Rust 코드는 안전하며 코드에서 키워드 unsafe
를 언급 하지 않으면 안전한 언어를 떠나지 않습니다. 이 코드의 나머지 부분은 unsafe
코드가 안전 Rust가 당신에게 너무 열심히 일한다는 보장을 모두 어길 수 있기 때문에 대부분 그 언어와 관련이 있습니다 . 반대로, unsafe
코드는 사악 하지 않으며 커뮤니티에서 그렇게 취급하지 않습니다 (그러나 필요하지 않을 때는 강력히 권장하지 않습니다).
안전한 코드가 사용하는 추상화를 만들 수 있기 때문에 위험하지만 중요합니다. 안전하지 않은 코드는 형식 시스템을 사용하여 다른 사람이 코드를 잘못 사용하지 못하도록 방지하므로 Rust 프로그램에 안전하지 않은 코드가 있으면 안전 코드를 방해 할 필요가 없습니다. Rust의 타입 시스템에는 C ++에는없는 툴이 있고 동시성 추상화를 구현하는 안전하지 않은 코드가 이러한 툴을 효과적으로 사용하기 때문에 다음과 같은 차이점이 있습니다.
비 차이 : 공유 / 변경 가능한 메모리
Rust는 메시지 전달에 더 중점을두고 공유 메모리를 매우 엄격하게 제어하지만 공유 메모리 동시성을 배제하지 않고 공통 추상화 (잠금, 원자 연산, 조건 변수, 동시 콜렉션)를 명시 적으로 지원합니다.
또한 C ++ 및 기능적 언어와 달리 Rust는 전통적인 명령형 데이터 구조를 정말 좋아합니다. 표준 라이브러리에는 영구 / 불변 링크 목록이 없습니다. 있다 std::collections::LinkedList
그러나 그것은처럼 std::list
C ++에서와 같은 이유로 좌절 std::list
(캐시의 잘못된 사용).
그러나 Rust는이 섹션의 제목 ( "공유 / 변경 가능 메모리")과 관련하여 C ++과 하나의 차이점이 있습니다. 즉, 메모리를 "공유 XOR 변경 가능", 즉 메모리가 동일하게 공유 및 변경 가능하지 않아야합니다. 시각. "자신의 스레드의 개인 정보 보호"에서 원하는대로 메모리를 변경하십시오. 이것을 공유 가변 메모리가 기본 옵션이며 널리 사용되는 C ++과 대조하십시오.
공유 xor- 변경 가능 패러다임은 아래의 차이점에 매우 중요하지만, 익숙해지는 데 시간이 걸리고 상당한 제약이 따르는 매우 다른 프로그래밍 패러다임이기도합니다. 때때로이 패러다임을 선택 해제해야합니다 (예 : 원자 유형) ( AtomicUsize
공유 가변 메모리의 본질 임). 잠금은 또한 동시 읽기 및 쓰기를 배제하므로 (한 스레드 쓰기 동안 다른 스레드는 읽거나 쓸 수 없음) 공유 xor 변경 가능 규칙을 준수합니다 .
비 차이 : 데이터 레이스는 정의되지 않은 동작 (UB)
Rust 코드에서 데이터 레이스를 시작하면 C ++에서와 마찬가지로 게임이 끝납니다. 모든 베팅이 종료되었으며 컴파일러는 원하는대로 할 수 있습니다.
그러나 안전한 Rust 코드에 데이터 레이스 (또는 그 문제에 대한 UB) 가 없다는 것은 확실한 보장 이 아닙니다 . 이것은 핵심 언어와 표준 라이브러리로 확장됩니다. unsafe
UB를 트리거 하는 (타사 라이브러리를 포함하지만 표준 라이브러리 제외) 사용하지 않는 Rust 프로그램을 작성할 수 있다면 버그로 간주되어 수정됩니다 (이미 여러 번 발생했습니다). 물론 이것은 C ++과는 대조적으로 UB로 프로그램을 작성하는 것이 쉽지 않습니다.
차이점 : 엄격한 잠금 규칙
C는 달리 ++, 녹 (의 잠금 std::sync::Mutex
, std::sync::RwLock
등) 소유 가 보호하는 것 데이터를. 잠금을 설정 한 다음 설명서에서만 잠금과 관련된 일부 공유 메모리를 조작하는 대신 잠금을 유지하지 않으면 공유 데이터에 액세스 할 수 없습니다. RAII 가드는 잠금을 유지하고 동시에 잠금 된 데이터에 대한 액세스를 제공합니다 (이 정도는 C ++로 구현할 수 있지만 std::
잠금 은 아닙니다 ). 수명 시스템은 잠금을 해제 한 후 데이터에 계속 액세스 할 수 없도록합니다 (RAII 가드 제거).
물론 유용한 데이터가없는 잠금 ( Mutex<()>
) 을 가질 수 있으며 , 해당 잠금과 명시 적으로 연결하지 않고 일부 메모리 만 공유 할 수 있습니다. 그러나 잠재적으로 동기화되지 않은 공유 메모리가 있어야합니다 unsafe
.
차이 : 우발적 공유 방지
메모리를 공유 할 수는 있지만 명시 적으로 요청할 때만 공유합니다. 예를 들어 메시지 전달 (예 :의 채널 std::sync
)을 사용하는 경우 수명 시스템은 다른 스레드로 보낸 후에 데이터에 대한 참조를 유지하지 않습니다. 잠금 뒤에서 데이터를 공유하려면 잠금을 명시 적으로 구성하여 다른 스레드에 제공하십시오. 동기화되지 않은 메모리를 나와 공유하려면 unsafe
을 사용해야 unsafe
합니다.
이것은 다음 지점과 관련이 있습니다.
차이점 : 스레드 안전성 추적
Rust 타입 시스템은 스레드 안전 개념을 추적합니다. 특히, Sync
특성은 데이터 경쟁의 위험없이 여러 스레드가 공유 할 수있는 유형을 나타내며 Send
한 스레드에서 다른 스레드로 이동할 수있는 유형을 나타냅니다 . 이는 프로그램 전체에서 컴파일러에 의해 시행되므로 라이브러리 디자이너는 이러한 정적 검사 없이는 어리석게 위험한 최적화를 수행합니다. 예를 들어, 여러 스레드에서 std::shared_ptr
a shared_ptr
가 사용되는 경우 UB를 피하기 위해 항상 원자 연산을 사용하여 참조 카운트를 조작하는 C ++ . 녹 있습니다 Rc
및 Arc
해당에 차이가있는 Rc
용도 이외의 원자 refcount는 운영 및 스레드 (즉, 구현하지 않습니다하지 않습니다 Sync
또는 Send
) 상태가 Arc
매우 흡사shared_ptr
(두 특성을 모두 구현).
유형 이unsafe
수동으로 동기화를 구현 하는 데 사용 하지 않는 경우 특성의 유무가 올바르게 추론됩니다.
차이 : 매우 엄격한 규칙
컴파일러가 일부 코드에 데이터 레이스 및 다른 UB가 없음을 절대 확신 할 수 없으면 period는 컴파일되지 않습니다 . 앞에서 언급 한 규칙과 기타 도구를 사용하면 훨씬 멀리 갈 수 있지만 조만간 올바른 작업을 수행하려고하지만 컴파일러의 통지를 벗어나는 미묘한 이유가 있습니다. 잠금이없는 까다로운 데이터 구조 일 수도 있지만 "공유 배열의 임의 위치에 쓰지만 모든 위치가 하나의 스레드 만 작성되도록 인덱스가 계산 됨"과 같은 평범한 것일 수도 있습니다.
이 시점에서 글 머리 기호를 물고 불필요한 동기화를 약간 추가하거나 컴파일러가 정확성을 보거나 (가능할 때가 종종 어렵거나 때로는 불가능한 경우) 코드를 변경하거나 코드에 빠질 수 있습니다 unsafe
. 그럼에도 불구하고 추가적인 정신적 오버 헤드이며 Rust는 unsafe
코드 의 정확성을 보장하지 않습니다 .
차이 : 적은 도구
앞에서 언급 한 차이점 때문에 Rust에서는 데이터 경쟁이있는 코드를 작성하는 경우 (또는 사용 후 사용 가능 또는 이중 사용 가능 또는 이중 사용 가능)가 훨씬 더 드 '니다. 이것이 좋지만, 이러한 오류를 추적하기위한 생태계가 청소년과 소규모 커뮤니티를 고려할 때 예상되는 것보다 훨씬 저개발 된 것은 불행한 부작용이 있습니다.
valgrind 및 LLVM의 thread sanitizer와 같은 도구는 원칙적으로 Rust 코드에 적용될 수 있지만, 실제로 작동하는지 여부는 도구마다 다릅니다 (특히 도구를 찾을 수 없기 때문에 작동하기 어려운 도구도 가능) 방법에 대한 -date 자원). Rust가 현재 실제 사양, 특히 공식 메모리 모델이 부족하다는 사실은 실제로 도움이되지 않습니다.
요컨대, unsafe
Rust 코드를 올바르게 작성하는 것은 C ++ 코드를 올바르게 작성하는 것보다 어렵 습니다. 두 언어 모두 기능과 위험 측면에서 대략 비교할 수 있습니다. 물론 이것은 전형적인 Rust 프로그램이 비교적 적은 양의 unsafe
코드 만을 포함 할 것이라는 사실에 비추어야만 하지만 C ++ 프로그램은 완전히 C ++입니다.