スマートポインタ、並列プログラミング、レーヨン


スタック対ヒープ


スタックは関数の最後に掃除されます.ヒープを掃除するための指示は、コンパイラによって加えられるさびにあります.

ポインタ対スマートポインタ


ポインタ-メモリアドレスを格納するオブジェクトで、メモリ内の位置を参照します
スマートポインタ-他のメタデータを格納しながら追加機能を提供するポインタをシミュレートします
スマートポインタはDELEFとDROP特徴を実装する

スマートポインタ


ボックス


fn main() {
    let b = Box::new(5);
    // uses 'Deref coercion' - converts a type into a reference to another type
    println!("b = {}", b);
}
fn main() {
    let x = 5;
    let y = Box::new(x);

    assert_eq!(5, x);
    assert_eq!(5, *y);
}

ドロップ


struct CustomSmartPointer {
    data: String,
}

impl Drop for CustomSmartPointer {
    fn drop(&mut self) {
        println!("Dropping CustomSmartPointer with data `{}`!", self.data);
    }
}

fn main() {
    let c = CustomSmartPointer {
        data: String::from("my stuff"),
    };
    let d = CustomSmartPointer {
        data: String::from("other stuff"),
    };
    println!("CustomSmartPointers created.");
}
手動でオブジェクトを削除できます.
fn main() {
    let c = CustomSmartPointer {
        data: String::from("some data"),
    };
    println!("CustomSmartPointer created.");
    drop(c);
    println!("CustomSmartPointer dropped before the end of main.");
}

スマートポインタを参照


我々がオブジェクトの複数の所有者を必要とするとき(グラフ-ノードが長いもう一つのノードがそれに対する端を持つので、リリースされることができません).
Lispライクリスト
enum List {
    Cons(i32, Rc<List>),
    Nil,
}

use crate::List::{Cons, Nil};
use std::rc::Rc;

fn main() {
    let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil)))));
    let b = Cons(3, Rc::clone(&a));
    let c = Cons(4, Rc::clone(&a));
}

フェルセル


ボックスとは異なり、所有者は実行時にチェックされます.
pub trait Messenger {
    fn send(&self, msg: &str);
}

pub struct LimitTracker<'a, T: Messenger> {
    messenger: &'a T,
    value: usize,
    max: usize,
}

impl<'a, T> LimitTracker<'a, T>
    where
        T: Messenger,
{
    pub fn new(messenger: &T, max: usize) -> LimitTracker<T> {
        LimitTracker {
            messenger,
            value: 0,
            max,
        }
    }

    pub fn set_value(&mut self, value: usize) {
        self.value = value;

        let percentage_of_max = self.value as f64 / self.max as f64;

        if percentage_of_max >= 1.0 {
            self.messenger.send("Error: You are over your quota!");
        } else if percentage_of_max >= 0.9 {
            self.messenger
                .send("Urgent warning: You've used up over 90% of your quota!");
        } else if percentage_of_max >= 0.75 {
            self.messenger
                .send("Warning: You've used up over 75% of your quota!");
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::cell::RefCell;

    struct MockMessenger {
        sent_messages: RefCell<Vec<String>>,
    }

    impl MockMessenger {
        fn new() -> MockMessenger {
            MockMessenger {
                sent_messages: RefCell::new(vec![]),
            }
        }
    }

    impl Messenger for MockMessenger {
        fn send(&self, message: &str) {
            self.sent_messages.borrow_mut().push(String::from(message));
        }
    }

    #[test]
    fn it_sends_an_over_75_percent_warning_message() {
        let mock_messenger = MockMessenger::new();
        let mut limit_tracker = LimitTracker::new(&mock_messenger, 100);

        limit_tracker.set_value(80);
        assert_eq!(mock_messenger.sent_messages.borrow().len(), 1);
    }
}

スレッド


use std::thread;
use std::time::Duration;

fn main() {
    thread::spawn(|| {
        for i in 1..10 {
            println!("hi number {} from the spawned thread!", i);
            thread::sleep(Duration::from_millis(1));
        }
    });

    for i in 1..5 {
        println!("hi number {} from the main thread!", i);
        thread::sleep(Duration::from_millis(1));
    }
}

結合スレッド


use std::thread;
use std::time::Duration;

fn main() {
    let handle = thread::spawn(|| {
        for i in 1..10 {
            println!("hi number {} from the spawned thread!", i);
            thread::sleep(Duration::from_millis(1));
        }
    });

    for i in 1..5 {
        println!("hi number {} from the main thread!", i);
        thread::sleep(Duration::from_millis(1));
    }

    handle.join().unwrap();
}

スレッド間のデータ転送


use std::sync::mpsc;
use std::thread;

fn main() {
    let (sender, receiver) = mpsc::channel();

    thread::spawn(move || {
        let val = String::from("hi");
        sender.send(val).unwrap();
    });

    let received = receiver.recv().unwrap();
    println!("Got: {}", received);
}

ミューテックス


use std::sync::Mutex;

fn main() {
    let m = Mutex::new(5);

    {
        let mut num = m.lock().unwrap();
        *num = 6;
    }

    println!("m = {:?}", m);
}

原子参照カウント


スレッドセーフ参照カウントポインタ.
use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    let counter = Arc::new(Mutex::new(0));
    let mut handles = vec![];

    for _ in 0..10 {
        let counter = Arc::clone(&counter);
        let handle = thread::spawn(move || {
            let mut num = counter.lock().unwrap();

            *num += 1;
        });
        handles.push(handle);
    }

    for handle in handles {
        handle.join().unwrap();
    }

    println!("Result: {}", *counter.lock().unwrap());
}

レーヨン図書館


[dependencies]
rayon = "1.4"
use rayon::prelude::*;
use std::borrow::Borrow;

/// Computes product of elements in vector in parallel
fn product_of_vec(input: &[i32]) -> i32 {
    input.par_iter()
        .map(|&i| i * i)
        .sum()
}

fn main() {
    let product = product_of_vec(vec![2, 4, 6].borrow());
    println!("Product is {}", product);
}

結合する


use std::sync::mpsc::channel;
use rayon::prelude::*;

fn main() {
    let (sender, receiver) = channel();

    (0..5).into_par_iter().for_each_with(sender, |s, x| s.send(x).unwrap());

    let mut res: Vec<_> = receiver.iter().collect();
    res.sort();

    assert_eq!(&res[..], &[0, 1, 2, 3, 4])
}

演習


ダイニング


導入


コンピューターサイエンスにおいて、ダイニング哲学者問題は、それらを解決するための同期問題とテクニックを説明するためにコンカレントアルゴリズム設計でしばしば使用される例問題です.
この問題についてはhereを読むことができます.

タスク

  • が、5人の哲学者です
  • が、5つの棒(デフォルト値0でミューテックスとして表される)
  • です
    それぞれの哲学者のために
  • 、新しい糸を作成します.
    哲学者は、左右の棒
  • をロックしようとします
    彼は両方の棒を持っていた後

  • ミリ秒の乱数
  • のスリープ
  • は、彼が食べて、増加したmutex(各々のフォークが使われた何回のカウンタ)
  • を印刷したと印刷します

  • 両方の棒
  • の上のリリース・ロック
    彼が考えている印刷

  • ミリ秒の乱数
  • のスリープ
    彼が考えるのを止めた印刷

  • すべてのスレッドに参加
  • は、各々の棒が使われた回数を印刷します(20でなければなりません)
  • ボーナス

  • はすべてのメッセージを最初に集めるためにstd::sync::mpsc::channelを使います
    最後に
  • 、すべてのメッセージ
  • を印刷してください

    解決策


    Dining philosophers
    Githubで私の学習錆レポをチェック!

    PETR 7555 / 学習錆