• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Atomic Operation
2
3
4## Basic Concepts
5
6In an OS that supports multiple tasks, modifying data in memory involves three steps: read data, modify data, and write data. However, the data may be simultaneously accessed by multiple tasks. If the data modification is interrupted by another task, an unexpected result will be caused.
7
8Although you can enable or disable interrupts to ensure expected results of multiple tasks, the system performance is affected.
9
10The ARMv6 architecture has introduced the **LDREX** and **STREX** instructions to support more discreet non-blocking synchronization of the shared memory. The atomic operations implemented thereby can ensure that the "read-modify-write" operations on the same data will not be interrupted, that is, the operation atomicity is ensured.
11
12
13## Working Principles
14
15OpenHarmony has encapsulated the **LDREX** and **STREX** in the ARMv6 architecture to provide a set of atomic operation APIs.
16
17- LDREX Rx, [Ry]
18  Reads the value in the memory and marks the exclusive access to the memory segment.
19  - Reads the 4-byte memory data pointed by the register **Ry** and saves the data to the **Rx** register.
20  - Adds an exclusive access flag to the memory area pointed by **Ry**.
21
22- STREX Rf, Rx, [Ry]
23  Checks whether the memory has an exclusive access flag. If yes, the system updates the memory value and clears the flag. If no, the memory is not updated.
24  - If there is an exclusive access flag, the system:
25    - Updates the **Rx** register value to the memory pointed to by the **Ry** register.
26    - Sets the **Rf** register to **0**.
27  - If there is no exclusive access flag:
28    - The memory is not updated.
29    - The system sets the **Rf** register to **1**.
30
31- Flag register
32  - If the flag register is **0**, the system exits the loop and the atomic operation is complete.
33  - If the flag register is **1**, the system continues the loop and performs the atomic operation again.
34
35
36## Development Guidelines
37
38
39### Available APIs
40
41The following table describes the APIs available for the OpenHarmony LiteOS-A kernel atomic operation module.
42
43**Table 1** APIs for atomic operations
44
45| Category    | API           | Description                       |
46| ------------ | ----------------------- | --------------------------- |
47| Read          | LOS_AtomicRead          | Reads 32-bit atomic data.          |
48| Read          | LOS_Atomic64Read        | Reads 64-bit atomic data.          |
49| Write          | LOS_AtomicSet           | Sets 32-bit atomic data.          |
50| Write          | LOS_Atomic64Set         | Sets 64-bit atomic data.          |
51| Add          | LOS_AtomicAdd           | Adds 32-bit atomic data.      |
52| Add          | LOS_Atomic64Add         | Adds 64-bit atomic data.      |
53| Add          | LOS_AtomicInc           | Adds 1 to 32-bit atomic data.       |
54| Add          | LOS_Atomic64Inc         | Adds 1 to 64-bit atomic data.       |
55| Add          | LOS_AtomicIncRet        | Adds 1 to 32-bit atomic data and returns the data. |
56| Add          | LOS_Atomic64IncRet      | Adds 1 to 64-bit atomic data and returns the data. |
57| Subtract          | LOS_AtomicSub           | Performs subtraction on 32-bit atomic data.      |
58| Subtract          | LOS_Atomic64Sub         | Performs subtraction on 64-bit atomic data.      |
59| Subtract          | LOS_AtomicDec           | Subtracts 1 from 32-bit atomic data.       |
60| Subtract          | LOS_Atomic64Dec         | Subtracts 1 from 64-bit atomic data.       |
61| Subtract          | LOS_AtomicDecRet        | Subtracts 1 from 32-bit atomic data and returns the result. |
62| Subtract          | LOS_Atomic64DecRet      | Subtracts 1 from 64-bit atomic data and returns the result. |
63| Swap        | LOS_AtomicXchgByte      | Swaps 8-bit memory data.           |
64| Swap        | LOS_AtomicXchg16bits    | Swaps 16-bit memory data.          |
65| Swap        | LOS_AtomicXchg32bits    | Swaps 32-bit memory data.          |
66| Swap        | LOS_AtomicXchg64bits    | Swaps 64-bit memory data.          |
67| Compare and swap| LOS_AtomicCmpXchgByte   | Compares and swaps 8-bit memory data. |
68| Compare and swap| LOS_AtomicCmpXchg16bits | Compares and swaps 16-bit memory data.|
69| Compare and swap| LOS_AtomicCmpXchg32bits | Compares and swaps 32-bit memory data.|
70| Compare and swap| LOS_AtomicCmpXchg64bits | Compares and swaps 64-bit memory data.|
71
72
73### How to Develop
74
75When multiple tasks perform addition, subtraction, and swap operations on the same memory data, use atomic operations to ensure predictability of results.
76
77> **NOTE**<br>
78>  Atomic operation APIs support only integers.
79
80
81### Development Example
82
83**Example Description**
84
85Call the atomic operation APIs and observe the result.
86
871. Create two tasks.
88   - Task 1: Call **LOS_AtomicInc** to add a global variable 100 times.
89   - Task 2: Call **LOS_AtomicDec** to subtract a global variable 100 times.
90
912. After the subtasks are complete, print the values of the global variable in the main task.
92
93**Sample Code**
94
95The sample code is as follows:
96
97
98```
99#include "los_hwi.h"
100#include "los_atomic.h"
101#include "los_task.h"
102
103UINT32 g_testTaskId01;
104UINT32 g_testTaskId02;
105Atomic g_sum;
106Atomic g_count;
107
108UINT32 Example_Atomic01(VOID)
109{
110    int i = 0;
111    for(i = 0; i < 100; ++i) {
112        LOS_AtomicInc(&g_sum);
113    }
114
115    LOS_AtomicInc(&g_count);
116    return LOS_OK;
117}
118
119UINT32 Example_Atomic02(VOID)
120{
121    int i = 0;
122    for(i = 0; i < 100; ++i) {
123        LOS_AtomicDec(&g_sum);
124    }
125
126    LOS_AtomicInc(&g_count);
127    return LOS_OK;
128}
129
130UINT32 Example_AtomicTaskEntry(VOID)
131{
132    TSK_INIT_PARAM_S stTask1={0};
133    stTask1.pfnTaskEntry = (TSK_ENTRY_FUNC)Example_Atomic01;
134    stTask1.pcName       = "TestAtomicTsk1";
135    stTask1.uwStackSize  = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
136    stTask1.usTaskPrio   = 4;
137    stTask1.uwResved     = LOS_TASK_STATUS_DETACHED;
138
139    TSK_INIT_PARAM_S stTask2={0};
140    stTask2.pfnTaskEntry = (TSK_ENTRY_FUNC)Example_Atomic02;
141    stTask2.pcName       = "TestAtomicTsk2";
142    stTask2.uwStackSize  = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
143    stTask2.usTaskPrio   = 4;
144    stTask2.uwResved     = LOS_TASK_STATUS_DETACHED;
145
146    LOS_TaskLock();
147    LOS_TaskCreate(&g_testTaskId01, &stTask1);
148    LOS_TaskCreate(&g_testTaskId02, &stTask2);
149    LOS_TaskUnlock();
150
151    while(LOS_AtomicRead(&g_count) != 2);
152    PRINTK("g_sum = %d\n", g_sum);
153
154    return LOS_OK;
155}
156```
157
158**Verification**
159
160
161```
162g_sum = 0
163```
164