Rust, 쉽게 하자!

Rust 입문 56

[Rust] Arc, Mutex (스레드의 데이터 공유)

5. Arc, Mutex. (스레드의 데이터 공유) 스레드 사이에 데이터를 교환하는 방법은 크게 두 가지가 있습니다. 앞 장에서 본 Message passing과 이번 장에서 볼 데이터 공유입니다. Message passing은 채널을 통해서 데이터를 진짜 주고받는 방식입니다. 반면에 데이터 공유 방식은 데이터를 주고 받는 대신 메모리의 데이터를 공유해서 스레드 사이의 통신을 달성하는 방법입니다. Rust는 스레드 사이의 데이터 공유를 달성하기 위해 Arc와 Mutex를 사용합니다. Arc와 Mutex는 스마트 포인터입니다. 이미 공부했던 스마트 포인터, Rc, Cell, RefCell 등은 하나의 스레드에 자리 잡고 있습니다. 다른 스레드의 스마트 포이터와 그 데이터를 사용할 수는 없습니다. Arc는 ..

Rust 입문 2022.10.28

[Rust] Message passing ( channel로 다른 스레드의 값 사용 하기 )

4. Message passing ( channel로 다른 스레드의 값 사용 하기 ) 앞 장에서는 main 스레드의 값(데이터)을 새로 만든 스레드에서 사용하는 방법을 살펴봤습니다. 여기서는 다른 스레드의 값을 사용하는 방법을 살펴보겠습니다. Rust는 스레드 사이의 데이터 교환을 위해 통신 채널을 사용합니다. 채널은 송신자와 수신자를 가지고 있습니다. 스레드 사이의 데이터 교환을 위해 먼저 채널의 송신자와 수신자를 생성하고 이것을 스레드에서 사용합니다. 이런 방법을 message passing이라고 합니다. 코드에서 살펴보겠습니다. 새로운 스레드에서 데이터를 보내고 main 스레드에서 데이터를 받고 있습니다. use std::sync::mpsc::channel; use std::thread; use s..

Rust 입문 2022.10.27

[Rust] 스레드에서 외부값 사용하기

3. 스레드에서 외부 값 사용하기 스레드는 서로 독립적으로 실행되기 때문에 만약 다른 스레드의 값을 사용하려면 특별한 방법이 필요합니다. 스레드를 하나 만들고 스레드 외부인 main 스레드에 값을 만들어 새로 만든 스레드에서 그 값을 사용하는 코드를 작성하고 실행해 보겠습니다. use std::thread; fn main() { let x = “hello".to_string(); // 1 thread::spawn(|| { println!("thread1: {}", x); // 2 }).join().expect("fail!"); } // 출력 ...에러 6 | thread::spawn(|| { | ^^ may outlive borrowed value `x` 7 | println!("thread1: {}",..

Rust 입문 2022.10.26

[Rust] 스레드 생성하기

2. 스레드 생성하기 먼저 스레드의 관점에서 main 함수를 살펴보겠습니다. fn main(){ println!("hello!"); } Rust는 main 함수에서 프로그램이 시작되고 끝납니다. main 함수를 실행하는 일도 하나의 스레드입니다. main 함수의 실행이 끝나고 스레드가 종료되면 프로그램이 종료됩니다. 이 점이 main 스레드의 특별한 점입니다. main 스레드 위에서 다른 스레드가 만들어져서 실행되면 그 스레드는 main 스레드의 자식 스레드가 됩니다. 자식 스레드가 끝나지 않아도 main 스레드가 끝나면 프로그램은 종료됩니다. 결과적으로 자식 스레드는 제대로 실행되지 않거나 실행될 기회를 잡지 못할 수도 있습니다. 스레드를 만들어서 과연 그런지 시험해 보겠습니다. 새로운 스레드를 만들 ..

Rust 입문 2022.10.25

[Rust] 동시성

1. 동시성 동시성은 한 번에 여러 가지 일을 한다는 의미입니다. 동시성은 병렬성과 구분해야 합니다. 《Rust 프로그래밍 언어(The Rust Programming Language)》에서는 동시성과 병렬성을 엄격하게 구분하지 않고 두리뭉실하게 받아들여 달라고 전제 한 뒤 설명을 이어 갑니다. 하지만 여기서는 우선 동시성과 병렬성을 개념적으로 구분 하고, 설명은 동시성을 스레드를 사용해 구현하는 것에만 초점을 맞추고자 합니다. 병렬성과 동시성을 구분하겠습니다. 일의 시작에서 끝까지의 타임라인이 있다고 가정 하겠습니다. 병렬 프로그래밍은 여러 가지의 일을 서로 간섭받지 않고 실제로 동시에 진행합니다. 하지만 동시성 프로그래밍은 여러 가지 일이 타임라인을 서로 나누어 사용합니다. 어떤 일을 찔끔하다가 멈추고..

Rust 입문 2022.10.24

[Rust] RefCell 그리고 Arc, Mutex

6. RefCell 앞 장에서 봤듯이, Cell에는 값을 넣었다 뺐다 할 수 있습니다. 그런데 만약 값의 크기가 아주 크다면 부담이 될 수 있습니다. 그래서 넣었다 빼서 사용하지 않고 참조를 통해 값을 빌려 와서 사용할 수 있도록 한 것이 RefCell입니다. 코드를 통해 알아보겠습니다. use std::borrow::Borrow; use std::cell::{BorrowError, Cell, Ref, RefCell}; fn main(){ let r = RefCell::new(10); // 1 println!("{:?}", r); let r1 = r.replace(100); // 2 println!("{:?} {:?}", r, r1); println!("{}", r.into_inner()); // 3 l..

Rust 입문 2022.10.23

[Rust] Cell

5. Cell Cell 타입은 mut 키워드를 사용하지 않아도 저장한 값을 변경할 수 있습니다. Cell 타입은 마치 물건 하나만 넣을 수 있는 상자와 같습니다. 이미 들어 있는 값을 꺼내서 사용하고 다른 값을 넣어 줄 수도 있고, 이미 들어 있는 값을 그냥 지우고 다른 값을 넣어 줄 수도 있습니다. 코드를 보면서 확인 해 보겠습니다. use std::cell::Cell; fn main(){ let c = Cell::new(10); // 1 println!("{:?}", c); let c1 = c.replace(5); // 2 println!("{}", c1); println!("{:?}", c); c.set(100); // 3 println!("{:?}", c); println!("{}", c.get(..

Rust 입문 2022.10.22

[Rust] Rc와 Weak

4. Rc와 Weak 1) Rc Rc는 Reference counting의 약자입니다. Reference counting은 참조된 횟수를 카운팅 하는 스마트 포인터입니다. 왜 참조된 횟수를 카운팅할까요? Rc는 하나의 데이터를 두고 복수의 소유권이 존재하는 것을 허용하는 스마트 포인터입니다. 소유권을 가진 변수가 여러 개다 보니 어느 한 변수의 소유권이 사라질 때 데이터까지 지워 버린다면 소유권을 가지고 있는 다른 변수까지 뜻하지 않게 값을 잃게 됩니다. 이런 일을 방지하기 위해 이 데이터에 대한 소유권을 얼마나 많은 변수들이 가지고 있는지 카운팅을 하는 것입니다. 데이터를 지우는 일은 카운팅이 0이 되어야만 일어나도록 설정되어 있습니다. 이런 방법을 통해 Rc는 한 데이터에 대해 복수의 소유권을 허용할..

Rust 입문 2022.10.21

[Rust] Vec

3. Vec Vec 타입은 배열처럼 여러 원소를 저장할 수 있습니다. 물론 저장되는 원소들의 데이터 타입은 같아야 합니다. 여기까지는 배열과 동일합니다. 하지만 Vec 타입은 String처럼 길이를 변화시킬 수 있습니다. 왜냐하면 Vec 타입의 원소는 배열의 원소와 달리 heap에 저장되기 때문입니다. 앞에서 String의 길이를 변화시켜 보았습니다. let mut s = String::from("welcome"); s.push_str(" to Rust"); Vec도 이와 같이 길이를 변화 시킬 수 있습니다. let mut vec1 = vec![1,2,3,4]; // 1 println!("{}", vec1.len()); // 2 vec1.push(5); // 3 println!("{}", vec1.len..

Rust 입문 2022.10.19

[Rust] Box

2. Box 스마트 포인터는 데이터의 실제 내용은 heap에 있고 그 주소를 가리키는 포인터를 비롯한 헤더는 stack에 있어서 스코프에 따른 소유권 규칙을 지킵니다. Box는 정확히 이런 특징을 가지고 있는 가장 기본적인 스마트 포인터입니다. heap에 저장되는 구조체를 하나 만들고 Box에 넣어 특징을 살펴보겠습니다. fn main(){ // 1 let mut point1 = Box::new(Point { x: 1, y: 1}); println!("{:?}", point1); let mut point2 = point1; // 재할당 println!("{:?}", point1); } // Point 구조체 선언 #[derive(Debug)] pub struct Point { pub x: i32, pub..

Rust 입문 2022.10.15
반응형