-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy path3-mutex.rs
71 lines (59 loc) · 1.82 KB
/
3-mutex.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
//! Mutex shared between tasks
//!
//! "When to use `Mutex` instead of a `RefCell`?" Both abstractions will give you an exclusive
//! (`&mut-`) reference to the data and that reference can survive across `yield`s (either explicit
//! , i.e. `task::yield`, or implicit, `.await`).
//!
//! The difference between the two is clear when contention occurs. If two or more tasks contend for
//! a `RefCell`, as in they both call `borrow_mut` on it, you'll get a panic. On the other hand, if
//! you use a `Mutex` in a similar scenario, i.e. both tasks call `lock` on it, then one of them
//! will "asynchronous" wait for (i.e. not resume until) the other task to release (releases) the
//! lock.
//!
//! Expected output:
//!
//! ```
//! B: before lock
//! A: before write
//! A: after releasing the lock
//! A: yield
//! B: 42
//! DONE
//! ```
//!
//! Try to replace the `Mutex` with `RefCell` and re-run the example
#![deny(unsafe_code)]
#![deny(warnings)]
#![no_main]
#![no_std]
use async_embedded::{task, unsync::Mutex};
use cortex_m::asm;
use cortex_m_rt::entry;
use cortex_m_semihosting::hprintln;
use nrf52 as _; // memory layout
use panic_udf as _; // panic handler
#[entry]
fn main() -> ! {
static mut X: Mutex<i64> = Mutex::new(0);
let mut lock = X.try_lock().unwrap();
task::spawn(async {
hprintln!("A: before write").ok();
*lock = 42;
drop(lock);
hprintln!("A: after releasing the lock").ok();
loop {
hprintln!("A: yield").ok();
task::r#yield().await;
}
});
task::block_on(async {
hprintln!("B: before lock").ok();
// cannot immediately make progress; context switch to A
let lock = X.lock().await;
hprintln!("B: {}", *lock).ok();
hprintln!("DONE").ok();
loop {
asm::bkpt();
}
})
}