Skip to content

Commit ae208b6

Browse files
committed
samples: philosophers: Add sync using Mutex/Condvar
Build a syncer that coordinates the forks using a single Mutex/Condvar pair, where the Mutex protects the data, and Condvar is used to coordinate. This is a common paradigm for shared synchronization. Signed-off-by: David Brown <[email protected]>
1 parent 5294bfa commit ae208b6

File tree

4 files changed

+86
-1
lines changed

4 files changed

+86
-1
lines changed

samples/philosophers/Kconfig

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ source "Kconfig.zephyr"
77

88
choice
99
prompt "Select Synchronization implementation"
10-
default SYNC_SYS_MUTEX
10+
default SYNC_CONDVAR
1111

1212
config SYNC_SYS_SEMAPHORE
1313
bool "Use sys::Semaphore to synchronize forks"
@@ -21,4 +21,10 @@ choice
2121
Use to have the dining philosophers sample use sys::Mutex, with one per fork, to
2222
synchronize.
2323

24+
config SYNC_CONDVAR
25+
bool "Use sync::Condvar and sync::Mutex to synchronize forks"
26+
help
27+
Use to have the dining philosophers sample use a single data structure, protected
28+
by a sync::Mutex and coordinated with a sync::Condvar, to synchronize.
29+
2430
endchoice

samples/philosophers/sample.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,8 @@ tests:
2525
min_ram: 32
2626
extra_configs:
2727
- CONFIG_SYNC_SYS_MUTEX=y
28+
sample.rust.philosopher.condvar:
29+
tags: introduction
30+
min_ram: 32
31+
extra_configs:
32+
- CONFIG_SYNC_CONDVAR=y

samples/philosophers/src/condsync.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright (c) 2024 Linaro LTD
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
//! # sync::Mutex/sync::Condvar implementation of ForkSync
5+
//!
6+
//! This implementation of the Fork synchronizer uses a single data object, protected by a
7+
//! `sync::Mutex`, and coordinated by a `sync::Condvar`.
8+
9+
use crate::{
10+
ForkSync,
11+
NUM_PHIL,
12+
};
13+
use zephyr::kobj_define;
14+
use zephyr::sync::Mutex;
15+
use zephyr::sync::Condvar;
16+
// use zephyr::time::Forever;
17+
18+
#[derive(Debug)]
19+
pub struct CondSync {
20+
/// The lock that holds the flag for each philosopher.
21+
lock: Mutex<[bool; NUM_PHIL]>,
22+
/// Condition variable to wake other threads.
23+
cond: Condvar,
24+
}
25+
26+
impl CondSync {
27+
#[allow(dead_code)]
28+
pub fn new() -> CondSync {
29+
let sys_mutex = MUTEX.init_once(()).unwrap();
30+
let sys_condvar = CONDVAR.init_once(()).unwrap();
31+
32+
let lock = Mutex::new_from([false; NUM_PHIL], sys_mutex);
33+
let cond = Condvar::new_from(sys_condvar);
34+
CondSync { lock, cond }
35+
}
36+
}
37+
38+
impl ForkSync for CondSync {
39+
fn take(&self, index: usize) {
40+
let mut lock = self.lock.lock().unwrap();
41+
while lock[index] {
42+
lock = self.cond.wait(lock).unwrap();
43+
}
44+
lock[index] = true;
45+
}
46+
47+
fn release(&self, index: usize) {
48+
let mut lock = self.lock.lock().unwrap();
49+
lock[index] = false;
50+
// No predictible waiter, so must wake everyone.
51+
self.cond.notify_all();
52+
}
53+
}
54+
55+
kobj_define! {
56+
static MUTEX: StaticMutex;
57+
static CONDVAR: StaticCondvar;
58+
}

samples/philosophers/src/lib.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,13 @@ use zephyr::{
2323

2424
// These are optional, based on Kconfig, so allow them to be unused.
2525
#[allow(unused_imports)]
26+
use crate::condsync::CondSync;
27+
#[allow(unused_imports)]
2628
use crate::sysmutex::SysMutexSync;
2729
#[allow(unused_imports)]
2830
use crate::semsync::semaphore_sync;
2931

32+
mod condsync;
3033
mod sysmutex;
3134
mod semsync;
3235

@@ -97,6 +100,19 @@ fn get_syncer() -> Vec<Arc<dyn ForkSync>> {
97100
result
98101
}
99102

103+
#[cfg(CONFIG_SYNC_CONDVAR)]
104+
fn get_syncer() -> Vec<Arc<dyn ForkSync>> {
105+
// Condvar version
106+
let syncer = Box::new(CondSync::new())
107+
as Box<dyn ForkSync>;
108+
let syncer: Arc<dyn ForkSync> = Arc::from(syncer);
109+
let mut result = Vec::new();
110+
for _ in 0..NUM_PHIL {
111+
result.push(syncer.clone());
112+
}
113+
result
114+
}
115+
100116
fn phil_thread(n: usize, syncer: Arc<dyn ForkSync>) {
101117
printkln!("Child {} started: {:?}", n, syncer);
102118

0 commit comments

Comments
 (0)