Posts tagged "kaist":
08 Mar 2026
KAIST CS431 Notes
Notes for KAIST CS431: Concurrent Programming.
Lecture videos are here.
Some topics may be out of the course scope, but come up along this note-taking process.
1. thread::scope
fn increment_both_half(data: &mut [i32]) { let (left, right) = data.split_at_mut(data.len() / 2); thread::scope(|scope| { scope.spawn(|_| { for x in left { *x += 1; } }); scope.spawn(|_| { for x in right { *x += 1; } }); }); println!(date); }
- Use
thread::scopewhen the threads must borrow data owned by the current stack frame. Otherwise`thread::spawn` would fail as it requires'staticor clone. - The
Scopeis only returned when all threads are joined (and consequently blocks), ensuring threads cannot outlive the borrowed data
2. unsafe fn
pub struct NonZeroUsize(usize); pub fn make_nonzero(x: usize) -> Option<NonZeroUsize> { if x == 0 { None } else { Some(NonZeroUsize(x)) } } pub unsafe fn consume_nonzero(x: u32) -> NonZeroUsize { NonZeroUsize(x) }
- Mark a function as
unsafewhen calling it requires the caller to upload some invariants which the compiler cannot guarantee. - Whether a function is
unsafehas nothing to do with its implementation, e.g., the API can be safe with unsafe code block. - Calling an
unsafe fnmust be wrapped withunsafe {}block.
3. object safety
- Object safety is a set of rules whether a trait can be used for dynamic dispatch, i.e.,
dyn trait. - These rules are already listed in 2024-12-28-interesting-rust-snippets.html.
- These rules ensure
- A sized
vtablecan be built for each concrete implementation of the trait (rule 1), and - The caller can know the type size returned from any trait method call (rule 2).
- A sized
4. async_trait
trait Data { fn fetch(&self) -> Pin<Box<dyn Future<Output = String> + Send>>; } // is equivalent to #[async_trait] trait Data { async fn fetch(&self) -> String; }
async_traitis only necessary for dynamic dispatch. For static dispatch, one can just writeasync fn fetch() -> String.- Why
Box<dyn Future>notimpl Future: to know type size during compiler time. Why
Pin: to prevent the future being moved and self-reference is broken when the future changes state, e.g.,async fn fetch(&self) { let data = String::from("hello"); let reference = &data; // reference to local variable is stored as absolute address some_async().await; // suspend here println!("{}", reference); // resume here, reference still needed }