---
title: "Dining philosophers"
canonical_url: https://developer.repebble.com/pebbleos/docs/samples/kernel/classic/dining_philosophers/
last_updated: 2026-11-13
sdk_version: 4.44
---
# Dining philosophers

Source: https://developer.repebble.com/pebbleos/docs/samples/kernel/classic/dining_philosophers/

This sample seats five threads at a table with five forks, mutexes, each needing the two next to it. Taking the left one first deadlocks when everyone holds one and waits for the next; taking the lower numbered one first cannot.

The deadlock is staged, as it otherwise takes bad luck: nobody goes on until all hold a fork, and a time limit on the second fork stands in for waiting forever. The fix is the rule the kernel and the drivers follow: locks are always taken in the same order.

Run:

`pbl samples samples/kernel/classic/dining_philosophers`

Boards:

every board

## Sources

src/main.c

```
#include \<stdatomic.h\>#include \<pbl/kernel/delay.h\>#include \<pbl/kernel/mutex.h\>#include \<pbl/kernel/sem.h\>#include \<pbl/kernel/thread.h\>#include \<pbl/logging/logging.h\>#define NUM\_PHILOSOPHERS 5#define MEALS 3struct philosopher {unsigned int seat;unsigned int meals;bool stuck;struct pbl\_thread thread;};static struct pbl\_mutex s\_forks[NUM\_PHILOSOPHERS];static struct philosopher s\_philosophers[NUM\_PHILOSOPHERS];static bool s\_ordered;static atomic\_uint s\_holding\_one;/\* Stuck philosophers keep their fork until main has counted them. \*/static PBL\_SEM\_DEFINE(s\_give\_up, 0, NUM\_PHILOSOPHERS);PBL\_THREAD\_STACK\_DEFINE(s\_stack\_0, 1024);PBL\_THREAD\_STACK\_DEFINE(s\_stack\_1, 1024);PBL\_THREAD\_STACK\_DEFINE(s\_stack\_2, 1024);PBL\_THREAD\_STACK\_DEFINE(s\_stack\_3, 1024);PBL\_THREAD\_STACK\_DEFINE(s\_stack\_4, 1024);static void prv\_philosopher(void \*arg) {struct philosopher \*philosopher = arg;struct pbl\_mutex \*first = &s\_forks[philosopher-\>seat];struct pbl\_mutex \*second = &s\_forks[(philosopher-\>seat + 1) % NUM\_PHILOSOPHERS];/\* The fix: everyone takes the lower numbered fork first, so no cycle of waiters can form. \*/if (s\_ordered && first \> second) {struct pbl\_mutex \*tmp = first;first = second;second = tmp;}while (philosopher-\>meals \< MEALS) {pbl\_mutex\_lock(first, PBL\_FOREVER);/\* \* A deadlock needs bad luck with the timing, which is staged here: nobody goes on until \* every philosopher holds a fork. With the fix they cannot all hold one. \*/atomic\_fetch\_add(&s\_holding\_one, 1);do {pbl\_thread\_yield();} while (!s\_ordered && atomic\_load(&s\_holding\_one) \< NUM\_PHILOSOPHERS);/\* The time limit stands in for the deadlock, which would otherwise end the sample here. \*/if (pbl\_mutex\_lock(second, PBL\_MSEC(50)) != 0) {philosopher-\>stuck = true;pbl\_sem\_take(&s\_give\_up, PBL\_FOREVER);pbl\_mutex\_unlock(first);return;}philosopher-\>meals++;pbl\_sleep\_ms(2);atomic\_fetch\_sub(&s\_holding\_one, 1);pbl\_mutex\_unlock(second);pbl\_mutex\_unlock(first);}}static int prv\_dinner(bool ordered) {void \*const stacks[NUM\_PHILOSOPHERS] = {s\_stack\_0, s\_stack\_1, s\_stack\_2, s\_stack\_3, s\_stack\_4};unsigned int stuck = 0;unsigned int meals = 0;int ret;s\_ordered = ordered;atomic\_store(&s\_holding\_one, 0);for (unsigned int i = 0; i \< NUM\_PHILOSOPHERS; i++) {const struct pbl\_thread\_attr attr = {.name = "philosopher",.entry = prv\_philosopher,.arg = &s\_philosophers[i],.prio = CONFIG\_KERNEL\_MAIN\_THREAD\_PRIO - 1,.privileged = true,.stack = stacks[i],.stack\_size = sizeof(s\_stack\_0),};s\_philosophers[i].seat = i;s\_philosophers[i].meals = 0;s\_philosophers[i].stuck = false;pbl\_thread\_create(&s\_philosophers[i].thread, &attr);}/\* Long enough for every meal, or for every time limit to pass. \*/pbl\_sleep\_ms(200);for (unsigned int i = 0; i \< NUM\_PHILOSOPHERS; i++) {stuck += s\_philosophers[i].stuck ? 1 : 0;meals += s\_philosophers[i].meals;pbl\_sem\_give(&s\_give\_up);}for (unsigned int i = 0; i \< NUM\_PHILOSOPHERS; i++) {ret =PBL\_POLL\_SLEEP\_MS(pbl\_thread\_state(&s\_philosophers[i].thread) == PBL\_THREAD\_DEAD, 1, 1000);if (ret != 0) {PBL\_LOG\_ERR("dinner: philosopher %u did not leave (%d)", i, ret);return ret;}}pbl\_sem\_reset(&s\_give\_up);PBL\_LOG\_INFO("dinner: %s: %u meals eaten, %u of %u philosophers stuck with one fork",ordered ? "lower fork first" : "left fork first", meals, stuck, NUM\_PHILOSOPHERS);return 0;}int main(void) {int ret;for (unsigned int i = 0; i \< NUM\_PHILOSOPHERS; i++) {pbl\_mutex\_init(&s\_forks[i]);}ret = prv\_dinner(false);if (ret != 0) {return ret;}ret = prv\_dinner(true);if (ret != 0) {return ret;}PBL\_LOG\_INFO("Sample done");return 0;}
```

## Output

```
dinner: left fork first: 0 meals eaten, 5 of 5 philosophers stuck with one fork
dinner: lower fork first: 15 meals eaten, 0 of 5 philosophers stuck with one fork
Sample done
```

Generated from PebbleOS [f4926c952](https://github.com/coredevices/pebbleos/commit/f4926c952bf9b82bce9e3cdb44645a59531c0ee9). This page is maintained in the pebbleos repository: [docs/samples/kernel/classic/dining\_philosophers.md](https://github.com/coredevices/pebbleos/blob/f4926c952bf9b82bce9e3cdb44645a59531c0ee9/docs/samples/kernel/classic/dining_philosophers.md).
