diff options
| author | Tyge Løvset <[email protected]> | 2023-06-04 22:16:38 +0200 |
|---|---|---|
| committer | Tyge Løvset <[email protected]> | 2023-06-04 22:28:40 +0200 |
| commit | 2d3250d2d35dda415840d8403b7b8957ca40914a (patch) | |
| tree | 4f1501bdcdd6d118c7176d0f89efd385307f31cc | |
| parent | c82dffc657faedba4c7af75792aa26287d9cf9bc (diff) | |
| download | STC-modified-2d3250d2d35dda415840d8403b7b8957ca40914a.tar.gz STC-modified-2d3250d2d35dda415840d8403b7b8957ca40914a.zip | |
Added dining_philosophers.c coroutine example.
Fixed cco_stop() when in state 0.
Renamed cco_timer_with(msec) => cco_timer_from(msec)
Renamed cco_sem_with(val) => cco_sem_from(val)
| -rw-r--r-- | include/stc/algo/coroutine.h | 15 | ||||
| -rw-r--r-- | misc/examples/dining_philosophers.c | 99 |
2 files changed, 106 insertions, 8 deletions
diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index d3f73229..05307b08 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -98,15 +98,13 @@ enum { #define cco_stop(co) \ do { \ - int* _state = &(co)->cco_state; \ - if (*_state > 0) *_state = cco_state_final; \ + int* _s = &(co)->cco_state; \ + if (*_s > 0) *_s = cco_state_final; \ + else if (*_s == 0) *_s = cco_state_done; \ } while (0) #define cco_reset(co) \ - do { \ - int* _state = &(co)->cco_state; \ - if (*_state == cco_state_done) *_state = 0; \ - } while (0) + (void)((co)->cco_state = 0) /* * Semaphore @@ -125,7 +123,8 @@ typedef struct { } while (0) #define cco_sem_release(sem) ++(sem)->count -#define cco_sem_with(value) ((cco_sem){value}) +#define cco_sem_from(value) ((cco_sem){value}) +#define cco_sem_set(sem, value) ((sem)->count = value) /* * Timer @@ -165,7 +164,7 @@ static inline void cco_timer_start(cco_timer* tm, long msec) { tm->start = clock(); } -static inline cco_timer cco_timer_with(long msec) { +static inline cco_timer cco_timer_from(long msec) { cco_timer tm = {msec*(CLOCKS_PER_SEC/1000), clock()}; return tm; } diff --git a/misc/examples/dining_philosophers.c b/misc/examples/dining_philosophers.c new file mode 100644 index 00000000..0bf421c6 --- /dev/null +++ b/misc/examples/dining_philosophers.c @@ -0,0 +1,99 @@ +// https://en.wikipedia.org/wiki/Dining_philosophers_problem +#include <stdio.h> +#include <stc/crand.h> +#include <stc/algo/coroutine.h> + +// Define the number of philosophers and forks +enum { + num_philosophers = 5, + num_forks = num_philosophers, +}; + +struct Philosopher { + int id; + cco_timer tm; + cco_sem* left_fork; + cco_sem* right_fork; + int cco_state; // required +}; + +struct Dining { + // Define semaphores for the forks + cco_sem forks[num_forks]; + struct Philosopher ph[num_philosophers]; + int ph_idx; + int cco_state; // required +}; + + +// Philosopher coroutine +void philosopher(struct Philosopher* p) +{ + cco_routine(p) { + while (1) { + int duration = (int)(1000 + crand() % 2000); // 1-3 seconds + printf("Philosopher %d is thinking for %d minutes...\n", p->id, duration/100); + cco_timer_await(&p->tm, duration); + + printf("Philosopher %d is hungry...\n", p->id); + cco_sem_await(p->left_fork); + cco_sem_await(p->right_fork); + + duration = (int)(500 + crand() % 1000); + printf("Philosopher %d is eating for %d minutes...\n", p->id, duration/100); + cco_timer_await(&p->tm, duration); + + cco_sem_release(p->left_fork); + cco_sem_release(p->right_fork); + } + + cco_final: + printf("Philosopher %d finished\n", p->id); + } +} + + +// Dining coroutine +void dining(struct Dining* d) +{ + cco_routine(d) { + for (int i = 0; i < num_forks; ++i) + cco_sem_set(&d->forks[i], 1); // all forks available + for (int i = 0; i < num_philosophers; ++i) { + cco_reset(&d->ph[i]); + d->ph[i].id = i + 1; + d->ph[i].left_fork = &d->forks[i]; + d->ph[i].right_fork = &d->forks[(i + 1) % num_forks]; + } + + while (1) { + for (d->ph_idx = 0; d->ph_idx < num_philosophers; ++d->ph_idx) { + philosopher(&d->ph[d->ph_idx]); + cco_yield(); + } + } + + cco_final: + for (int i = 0; i < num_philosophers; ++i) { + cco_stop(&d->ph[i]); + philosopher(&d->ph[i]); + } + puts("Dining finished"); + } +} + + +int main() +{ + struct Dining dine; + cco_reset(&dine); + cco_timer tm = cco_timer_from(10000); + csrand((uint64_t)time(NULL)); + + while (!cco_done(&dine)) { + if (cco_timer_expired(&tm)) + cco_stop(&dine); + dining(&dine); + cco_sleep(1); + } +} |
