Atomic Operations
An atomic operation refers to an indivisible operation that is either executed completely successfully or not executed at all. No interruptions are allowed during the execution of an atomic operation. If an interruption occurs, the result of the operation cannot be guaranteed. Atomic operations are often used in multi-threaded programming to ensure that concurrent execution between multiple threads does not cause problems such as data contention. When implementing atomic operations, hardware instructions or atomic operation functions provided by the operating system are usually used to ensure the atomicity of the operation. At the application level, atomic operations can be used to implement some advanced synchronization and concurrency control mechanisms. For example, in multi-threaded programming, if multiple threads need to access the same shared variable, in order to avoid data contention problems, atomic operations can be used to ensure that operations on the variable are atomic. Let's take the ARM kernel executing an i++ operation as an example:
We see that for coding engineers, we only need one line of code to execute an i++ operation. After compilation, i++ will be translated into three instructions. Therefore, these three instructions may be interrupted by system scheduling, interrupts and other events. Therefore, in some scenarios, we need to execute the above operations in one go. Atomic operations have this capability.
In RT-Thread, we can protect critical section resources by switching global interrupts, locking the scheduler, etc. Other OSes also provide similar operations. If atomic operations are used, we can improve the execution efficiency of critical section codes and greatly improve the operating efficiency of the system. At the same time, it will also reduce the complexity of programming to a certain extent. The following is an example of a simple variable increment:
The protection of critical area is realized by switching global interrupt:
If we use the atomic operation API provided by RT-Thread, we can do this:
Obviously, the atomic operation method is simpler and avoids the performance loss caused by switching global interrupts.
RT-Thread provides atomic operation support for 32-bit ARM, 32-bit RISC-V and 64-bit RISC-V cores that support atomic operations. It uses the atomic operation instructions and related instructions of the corresponding platform to implement it. It is supported by default and users do not need to worry about the implementation. When using it, users only need to include it in the project rtatomic.h
to use the atomic operation API provided by the file. The detailed support is as follows:
Instruction architecture
Atomic instruction support of RT-Thread adapter kernel
32-bit ARM
Most cores using the ARM instruction set support atomic instructions. The cores that do not support atomic instructions include cortex-m0, cortex-m0+, arm926, lpc214x, lpc24xx, s3c24x0, and AT91SAM7.
32-bit RISC-V
Most kernels using the RV32 instruction set support atomic operations. Some BSPs that do not support atomic operations include: core-v-mcu, rv32m1_vega.
64-bit RISC-V
Most kernels using the RV64 instruction set support atomic operations. Some BSPs that do not support atomic operations include juicevm.
If the tool chain supports the atomic operation API of the C11 standard, you can also use menuconfig to configure RT_USING_STDC_ATOMIC
the macro. In this case, rtatomic.h
the macro provided in the call will actually call the API provided by the C11 standard. The configuration method of menuconfig is as follows:
For the above kernels that do not support atomic operations, when users include and use the API provided by this file in their projects rtatomic.h
, atomic operations will be soft-implemented by switching global interrupts.
RT-Thread provides 11 frequently used atomic operation APIs.
RT-Thread Atomic Operation API
effect
rt_atomic_t rt_hw_atomic_load(volatile rt_atomic_t *ptr)
Atomically load a word from address ptr
void rt_atomic_store(volatile rt_atomic_t *ptr, rt_atomic_t val)
Atomically write val to address ptr
rt_atomic_t rt_atomic_exchange(volatile rt_atomic_t *ptr, rt_atomic_t val)
Atomically replace the value at the address of ptr with val
rt_atomic_t rt_atomic_add(volatile rt_atomic_t *ptr, rt_atomic_t val)
Atomically adds the value at address ptr to val
rt_atomic_t rt_atomic_sub(volatile rt_atomic_t *ptr, rt_atomic_t val)
Atomically subtract the value at address ptr from val
rt_atomic_t rt_atomic_xor(volatile rt_atomic_t *ptr, rt_atomic_t val)
Atomically XOR the value at address ptr with val
rt_atomic_t rt_atomic_and(volatile rt_atomic_t *ptr, rt_atomic_t val)
Atomically AND the value at address ptr with val
rt_atomic_t rt_atomic_or(volatile rt_atomic_t *ptr, rt_atomic_t val)
Atomically bitwise OR the value at address ptr with val
rt_atomic_t rt_atomic_flag_test_and_set(volatile rt_atomic_t *ptr)
Atomically sets the value at address ptr to 1
void rt_atomic_flag_clear(volatile rt_atomic_t *ptr)
Atomically clear the value at the address ptr to 0
rt_atomic_t rt_atomic_compare_exchange_strong(volatile rt_atomic_t *ptr, rt_atomic_t *old, rt_atomic_t new)
Atomically compares and exchanges the value at the address ptr with val, and returns the comparison result
Detailed explanation of atomic operation functions:
The semantics of this operation function is: use atomic operation to load a word from the 4-byte space pointed to by the ptr address.
parameter
describe
ptr
Atomic object address
Return Value
Returns the 4-byte data at the address of ptr
The semantics of this operation function is: use atomic operation to write val into the 4-byte space pointed to by the ptr address.
parameter
describe
ptr
Atomic object address
val
Expected data to be written to the address ptr
Return Value
NULL
The semantics of this operation function is: use atomic operation to exchange the data in the 4-byte space pointed to by the ptr address with val, and return the 4-byte data before modification at the ptr address.
parameter
describe
ptr
Atomic object address
val
Expected data to be exchanged
Return Value
Returns the 4 bytes of data before the swap at the ptr address
The semantics of this operation function is: use atomic operation to add the 4-byte data pointed to by the ptr address to val, write the result to the 4-byte space pointed to by the ptr address, and return the 4-byte data before modification at the ptr address.
parameter
describe
ptr
Atomic object address
val
Expected value to be added
Return Value
Returns the 4 bytes of data before modification at the ptr address
The semantics of this operation function is: use atomic operation to subtract val from the 4-byte data pointed to by the ptr address, write the result to the 4-byte space pointed to by the ptr address, and return the 4-byte data before modification at the ptr address.
parameter
describe
ptr
Atomic object address
val
Expected value to be subtracted
Return Value
Returns the 4 bytes of data before modification at the ptr address
The semantics of this operation function is: use atomic operation to perform bitwise XOR on the 4-byte data pointed to by the ptr address and val, write the result to the 4-byte space pointed to by the ptr address, and return the 4-byte data before modification at the ptr address.
parameter
describe
ptr
Atomic object address
val
Expected XOR value
Return Value
Returns the 4 bytes of data before modification at the ptr address
The semantics of this operation function is: use atomic operation to perform bitwise AND operation on the 4-byte data pointed to by the ptr address and val, write the result to the 4-byte space pointed to by the ptr address, and return the 4-byte data before modification at the ptr address.
parameter
describe
ptr
Atomic object address
val
Expected value to be ANDed
Return Value
Returns the 4 bytes of data before modification at the ptr address
The semantics of this operation function is: use atomic operation to perform bitwise OR of the 4-byte data pointed to by the ptr address and val, write the result to the 4-byte space pointed to by the ptr address, and return the 4-byte data before modification at the ptr address.
parameter
describe
ptr
Atomic object address
val
Expected OR value
Return Value
Returns the 4 bytes of data before modification at the ptr address
Atomic flag checking and setting
The semantics of this operation function is: set the 4-byte atomic flag pointed to by the ptr address, and return the value of the atomic flag object before the setting operation. If the 4-byte data pointed to by the ptr address was previously in state 0, then after this operation, the state of the atomic flag object changes to state 1, and returns 0. If the 4-byte data pointed to by the ptr address was previously in state 1, then after this operation, it is still in state 1, and returns 1. So if we use the atomic flag object as a "lock", we can judge the return value of this function interface. If it returns 0, it means that the lock is successful, and related modification operations can be performed on the multi-threaded shared object; if the return is state 1, the atomic flag has been occupied by other threads and needs to wait for release.
parameter
describe
ptr
Atomic object address. The 4-byte data pointed to by the address can only be 0 or 1.
Return Value
Set Status
The semantics of this operation function is: clear the flag, clear the flag to 0, and clear the atomic flag pointed to by the ptr address. If we use the atomic flag object as a "lock", then performing this operation is equivalent to releasing the lock.
parameter
describe
ptr
Atomic object address
Return Value
NULL
The semantics of this operation function is: the first parameter points to an atomic type object; the second parameter points to the object to be compared, and if the comparison fails, the operation will copy the current value of the atomic object to the object pointed to by the parameter; the third parameter specifies the value stored in the atomic object. If the comparison succeeds, the new value will be stored in the atomic object and 1 will be returned; if the comparison fails, the value of the current atomic object will be copied to the object pointed to by old and 0 will be returned.
parameter
describe
ptr
Atomic object address
old
Objects being compared
new
The object to be updated
Return Value
Comparison results
Include it in your project rtatomic.h
, and then add the example to your project for simple atomic operation verification.
Last updated