blob: 8ff1ea33e9aabaaaf0bee0e60092a0ed8269af72 [file] [log] [blame]
.. zephyr:code-sample:: dining-philosophers
:name: Dining Philosophers
:relevant-api: semaphore_apis mutex_apis stack_apis thread_apis fifo_apis lifo_apis
Implement a solution to the Dining Philosophers problem using Zephyr kernel services.
Overview
********
An implementation of a solution to the Dining Philosophers problem (a classic multi-thread
synchronization problem). This particular implementation demonstrates the usage of multiple
preemptible and cooperative threads of differing priorities, as well as dynamic mutexes and thread
sleeping.
The philosopher always tries to get the lowest fork first (f1 then f2). When done, he will give
back the forks in the reverse order (f2 then f1). If he gets two forks, he is ``EATING``.
Otherwise, he is ``THINKING``. Transitional states are shown as well, such as ``STARVING`` when the
philosopher is hungry but the forks are not available, and ``HOLDING ONE FORK`` when a philosopher
is waiting for the second fork to be available.
Each Philosopher will randomly alternate between the ``EATING`` and ``THINKING`` states.
It is possible to run the demo in ``coop-only`` or ``preempt-only`` mode. To achieve this, set these
values for ``CONFIG_NUM_COOP_PRIORITIES`` and ``CONFIG_NUM_PREEMPT_PRIORITIES`` in :file:`prj.conf`:
preempt-only
.. code-block:: cfg
CONFIG_NUM_PREEMPT_PRIORITIES=6
CONFIG_NUM_COOP_PRIORITIES=0
coop-only
.. code-block:: cfg
CONFIG_NUM_PREEMPT_PRIORITIES=0
CONFIG_NUM_COOP_PRIORITIES=6
In these cases, the philosopher threads will run with priorities 0 to 5 (preempt-only) and -7 to -2
(coop-only).
Building and Running
********************
This project outputs to the console. It can be built and executed on QEMU as follows:
.. zephyr-app-commands::
:zephyr-app: samples/philosophers
:host-os: unix
:board: qemu_x86
:goals: run
:compact:
Sample Output
=============
.. code-block::
Philosopher 0 [P: 3] HOLDING ONE FORK
Philosopher 1 [P: 2] HOLDING ONE FORK
Philosopher 2 [P: 1] EATING [ 1900 ms ]
Philosopher 3 [P: 0] THINKING [ 2500 ms ]
Philosopher 4 [C:-1] THINKING [ 2200 ms ]
Philosopher 5 [C:-2] THINKING [ 1700 ms ]
Exit QEMU by pressing :kbd:`CTRL+A` :kbd:`x`.
Debug Threads
*************
The philosophers sample by default enables :kconfig:option:`CONFIG_DEBUG_THREAD_INFO`. This allows
tools like OpenOCD and J-link to inspect thread data using ``info threads``.
.. zephyr-app-commands::
:zephyr-app: samples/philosophers
:host-os: unix
:board: <board_name>
:goals: debug
:compact:
OpenOCD Sample Output
=====================
.. code-block::
Thread 1 received signal SIGINT, Interrupt.
[Switching to Thread 537003160]
arch_cpu_idle () at zephyr/mainline/zephyr/arch/arm/core/cpu_idle.S:107
107 cpsie i
(gdb) i threads
Id Target Id Frame
* 1 Thread 537003160 (Name: idle 00, prio:40,useropts:1) arch_cpu_idle () at zephyr/mainline/zephyr/arch/arm/core/cpu_idle.S:107
Info : Getting thread 537002984 reg list
2 Thread 537002984 (Name: Philosopher 5, prio:-2,useropts:4) 0x08001404 in arch_irq_unlock (key=0) at zephyr/mainline/zephyr/include/arch/arm/asm_inline_gcc.h:95
Info : Getting thread 537002808 reg list
3 Thread 537002808 (Name: Philosopher 4, prio:-1,useropts:4) 0x08001404 in arch_irq_unlock (key=0) at zephyr/mainline/zephyr/include/arch/arm/asm_inline_gcc.h:95
Info : Getting thread 537002632 reg list
4 Thread 537002632 (Name: Philosopher 3, prio:0,useropts:4) 0x08001404 in arch_irq_unlock (key=0) at zephyr/mainline/zephyr/include/arch/arm/asm_inline_gcc.h:95
Info : Getting thread 537002456 reg list
5 Thread 537002456 (Name: Philosopher 2, prio:1,useropts:4) 0x08001404 in arch_irq_unlock (key=0) at zephyr/mainline/zephyr/include/arch/arm/asm_inline_gcc.h:95
Info : Getting thread 537002280 reg list
6 Thread 537002280 (Name: Philosopher 1, prio:2,useropts:4) 0x08001404 in arch_irq_unlock (key=0) at zephyr/mainline/zephyr/include/arch/arm/asm_inline_gcc.h:95
Info : Getting thread 537002104 reg list
7 Thread 537002104 (Name: Philosopher 0, prio:3,useropts:4) 0x08001404 in arch_irq_unlock (key=0) at zephyr/mainline/zephyr/include/arch/arm/asm_inline_gcc.h:95
.. code-block::
Philosopher 0 [P: 3] STARVING
Philosopher 1 [P: 2] HOLDING ONE FORK
Philosopher 2 [P: 1] EATING [ 400 ms ]
Philosopher 3 [P: 0] THINKING [ 525 ms ]
Philosopher 4 [C:-1] HOLDING ONE FORK
Philosopher 5 [C:-2] EATING [ 625 ms ]
J-Link Sample Output
====================
.. code-block::
Thread 2 received signal SIGTRAP, Trace/breakpoint trap.
[Switching to Thread 537920592]
arch_cpu_idle () at zephyr/mainline/zephyr/arch/arm/core/cpu_idle.S:107
107 cpsie i
(gdb) i threads
Id Target Id Frame
* 2 Thread 537920592 (idle 00 UNKNOWN PRIO 40) arch_cpu_idle () at zephyr/mainline/zephyr/arch/arm/core/cpu_idle.S:107
3 Thread 537919536 (Philosopher 0 PENDING PRIO 3) arch_swap (key=0) at zephyr/mainline/zephyr/arch/arm/core/swap.c:53
4 Thread 537919712 (Philosopher 1 SUSPENDED PRIO 2) arch_swap (key=key@entry=0) at zephyr/mainline/zephyr/arch/arm/core/swap.c:53
5 Thread 537919888 (Philosopher 2 SUSPENDED PRIO 1) arch_swap (key=key@entry=0) at zephyr/mainline/zephyr/arch/arm/core/swap.c:53
6 Thread 537920064 (Philosopher 3 SUSPENDED PRIO 0) arch_swap (key=key@entry=0) at zephyr/mainline/zephyr/arch/arm/core/swap.c:53
7 Thread 537920240 (Philosopher 4 PENDING PRIO 255) arch_swap (key=0) at zephyr/mainline/zephyr/arch/arm/core/swap.c:53
8 Thread 537920416 (Philosopher 5 SUSPENDED PRIO 254) arch_swap (key=key@entry=0) at zephyr/mainline/zephyr/arch/arm/core/swap.c:53
.. code-block::
Philosopher 0 [P: 3] STARVING
Philosopher 1 [P: 2] EATING [ 475 ms ]
Philosopher 2 [P: 1] THINKING [ 700 ms ]
Philosopher 3 [P: 0] THINKING [ 525 ms ]
Philosopher 4 [C:-1] HOLDING ONE FORK
Philosopher 5 [C:-2] EATING [ 625 ms ]