139 lines
3.4 KiB
ReStructuredText
139 lines
3.4 KiB
ReStructuredText
.. _semaphores_v2:
|
|
|
|
Semaphores
|
|
##########
|
|
|
|
A :dfn:`semaphore` is a kernel object that implements a traditional
|
|
counting semaphore.
|
|
|
|
.. contents::
|
|
:local:
|
|
:depth: 2
|
|
|
|
Concepts
|
|
********
|
|
|
|
Any number of semaphores can be defined. Each semaphore is referenced
|
|
by its memory address.
|
|
|
|
A semaphore has the following key properties:
|
|
|
|
* A **count** that indicates the number of times the semaphore can be taken.
|
|
A count of zero indicates that the semaphore is unavailable.
|
|
|
|
* A **limit** that indicates the maximum value the semaphore's count
|
|
can reach.
|
|
|
|
A semaphore must be initialized before it can be used. Its count must be set
|
|
to a non-negative value that is less than or equal to its limit.
|
|
|
|
A semaphore may be **given** by a thread or an ISR. Giving the semaphore
|
|
increments its count, unless the count is already equal to the limit.
|
|
|
|
A semaphore may be **taken** by a thread. Taking the semaphore
|
|
decrements its count, unless the semaphore is unavailable (i.e. at zero).
|
|
When a semaphore is unavailable a thread may choose to wait for it to be given.
|
|
Any number of threads may wait on an unavailable semaphore simultaneously.
|
|
When the semaphore is given, it is taken by the highest priority thread
|
|
that has waited longest.
|
|
|
|
.. note::
|
|
The kernel does allow an ISR to take a semaphore, however the ISR must
|
|
not attempt to wait if the semaphore is unavailable.
|
|
|
|
Implementation
|
|
**************
|
|
|
|
Defining a Semaphore
|
|
====================
|
|
|
|
A semaphore is defined using a variable of type :c:type:`struct k_sem`.
|
|
It must then be initialized by calling :cpp:func:`k_sem_init()`.
|
|
|
|
The following code defines a semaphore, then configures it as a binary
|
|
semaphore by setting its count to 0 and its limit to 1.
|
|
|
|
.. code-block:: c
|
|
|
|
struct k_sem my_sem;
|
|
|
|
k_sem_init(&my_sem, 0, 1);
|
|
|
|
Alternatively, a semaphore can be defined and initialized at compile time
|
|
by calling :c:macro:`K_SEM_DEFINE`.
|
|
|
|
The following code has the same effect as the code segment above.
|
|
|
|
.. code-block:: c
|
|
|
|
K_SEM_DEFINE(my_sem, 0, 1);
|
|
|
|
Giving a Semaphore
|
|
==================
|
|
|
|
A semaphore is given by calling :cpp:func:`k_sem_give()`.
|
|
|
|
The following code builds on the example above, and gives the semaphore to
|
|
indicate that a unit of data is available for processing by a consumer thread.
|
|
|
|
.. code-block:: c
|
|
|
|
void input_data_interrupt_handler(void *arg)
|
|
{
|
|
/* notify thread that data is available */
|
|
k_sem_give(&my_sem);
|
|
|
|
...
|
|
}
|
|
|
|
Taking a Semaphore
|
|
==================
|
|
|
|
A semaphore is taken by calling :cpp:func:`k_sem_take()`.
|
|
|
|
The following code builds on the example above, and waits up to 50 milliseconds
|
|
for the semaphore to be given.
|
|
A warning is issued if the semaphore is not obtained in time.
|
|
|
|
.. code-block:: c
|
|
|
|
void consumer_thread(void)
|
|
{
|
|
...
|
|
|
|
if (k_sem_take(&my_sem, K_MSEC(50)) != 0) {
|
|
printk("Input data not available!");
|
|
} else {
|
|
/* fetch available data */
|
|
...
|
|
}
|
|
...
|
|
}
|
|
|
|
Suggested Uses
|
|
**************
|
|
|
|
Use a semaphore to control access to a set of resources by multiple threads.
|
|
|
|
Use a semaphore to synchronize processing between a producing and consuming
|
|
threads or ISRs.
|
|
|
|
Configuration Options
|
|
*********************
|
|
|
|
Related configuration options:
|
|
|
|
* None.
|
|
|
|
APIs
|
|
****
|
|
|
|
The following semaphore APIs are provided by :file:`kernel.h`:
|
|
|
|
* :c:macro:`K_SEM_DEFINE`
|
|
* :cpp:func:`k_sem_init()`
|
|
* :cpp:func:`k_sem_give()`
|
|
* :cpp:func:`k_sem_take()`
|
|
* :cpp:func:`k_sem_reset()`
|
|
* :cpp:func:`k_sem_count_get()`
|