原子量
在本章的开篇我们介绍了变量 V 的自增操作在多线程环境下存在混乱风险,为了解决此问题,我们提出了加入一把锁保护变量 V 的自增操作的解决方案。
当我们的程序存在较多类似于变量 V 这样的变量或对这样的变量访问较多时,我们的程序必然存在较多的锁和锁操作,一方面这使得我们的程序难以编写和维护,另一方面不合理的锁操作可能会发生死锁。
为了避免这些问题,SylixOS 提供了原子量类型 atomic_t 及其相关 API,原子量类型可储存一个整型类型的值,同时使用原子量 API 对原子量进行的操作是一个原子操作,因为原子操作不可打断,这样在多线程环境下也就不会存在混乱风险。
SylixOS 原子量的类型为 atomic_t。使用时需要定义一个 atomic_t 类型的变量,如:
atomic_t atomic;
原子量
原子量的设置和获取
#include <SylixOS.h>
VOID Lw_Atomic_Set(INT iVal, atomic_t *patomic);
函数 Lw_Atomic_Set 原型分析:
- 参数 iVal 是需要设置的值。
- 参数 patomic 是原子量的指针。
#include <SylixOS.h>
INT Lw_Atomic_Get(atomic_t *patomic);
函数 Lw_Atomic_Get 原型分析:
- 此函数成功时返回原子量的值,失败时返回-1 并设置错误号。
- 参数 patomic 是原子量的指针。
原子量的加和减
#include <SylixOS.h>
INT Lw_Atomic_Add(INT iVal, atomic_t *patomic);
函数 Lw_Atomic_Add 原型分析:
- 此函数成功时返回原子量的新值,失败时返回-1 并设置错误号。
- 参数 iVal 是需要加上的值。
- 参数 patomic 是原子量的指针。
#include <SylixOS.h>
INT Lw_Atomic_Sub(INT iVal, atomic_t *patomic);
函数 Lw_Atomic_Sub 原型分析:
- 此函数成功时返回原子量的新值,失败时返回-1 并设置错误号。
- 参数 iVal 是需要减去的值。
- 参数 patomic 是原子量的指针。
原子量的自增和自减
#include <SylixOS.h>
INT Lw_Atomic_Inc(atomic_t *patomic);
INT Lw_Atomic_Dec(atomic_t *patomic);
以上两个函数原型分析:
- 函数成功时返回原子量的新值,失败时返回-1 并设置错误号。
- 参数 patomic 是原子量的指针。
原子量的逻辑位操作
#include <SylixOS.h>
INT Lw_Atomic_And(INT iVal, atomic_t *patomic);
函数 Lw_Atomic_And 原型分析:
- 此函数成功时返回原子量的新值,失败时返回-1 并设置错误号。
- 参数 iVal 是需要进行逻辑位与操作的值。
- 参数 patomic 是原子量的指针。
#include <SylixOS.h>
INT Lw_Atomic_Nand(INT iVal, atomic_t *patomic);
函数 Lw_Atomic_Nand 原型分析:
- 此函数成功时返回原子量的新值,失败时返回-1 并设置错误号。
- 参数 iVal 是需要进行逻辑位与非操作的值。
- 参数 patomic 是原子量的指针。
#include <SylixOS.h>
INT Lw_Atomic_Or(INT iVal, atomic_t *patomic);
函数 Lw_Atomic_Or 原型分析:
- 此函数成功时返回原子量的新值,失败时返回-1 并设置错误号。
- 参数 iVal 是需要进行逻辑位或操作的值。
- 参数 patomic 是原子量的指针。
#include <SylixOS.h>
INT Lw_Atomic_Xor(INT iVal, atomic_t *patomic);
函数 Lw_Atomic_Xor 原型分析:
- 此函数成功时返回原子量的新值,失败时返回-1 并设置错误号。
- 参数 iVal 是需要进行逻辑位异或操作的值。
- 参数 patomic 是原子量的指针。
原子量的交换操作
#include <SylixOS.h>
INT Lw_Atomic_Swp(INT iVal, atomic_t *patomic);
函数 Lw_Atomic_Swp 原型分析:
- 此函数成功时返回原子量的旧值(进行操作前的值),失败时返回-1 并设置错误号。
- 参数 iVal 是需要设置的值。
- 参数 patomic 是原子量的指针。
下面程序展示了 POSIX 原子量的使用,程序创建两个线程,两个线程分别对原子量 _G_atomicCount 进行打印和自增操作。
#include <SylixOS.h>
static atomic_t _G_atomicCount;
static PVOID tTestA (PVOID pvArg)
{
while (1) {
printf("tTestA(): count = %d\n", API_AtomicGet(&_G_atomicCount));
Lw_Time_SSleep(1);
}
return (LW_NULL);
}
static PVOID tTestB (PVOID pvArg)
{
while (1) {
Lw_Atomic_Inc(&_G_atomicCount);
Lw_Time_SSleep(1);
}
return (LW_NULL);
}
int main (int argc, char *argv[])
{
LW_HANDLE hThreadAId;
LW_HANDLE hThreadBId;
Lw_Atomic_Set(0, &_G_atomicCount);
hThreadAId = Lw_Thread_Create("t_testa", tTestA, LW_NULL, LW_NULL);
if (hThreadAId == LW_OBJECT_HANDLE_INVALID) {
printf("t_testa create failed.\n");
return (-1);
}
hThreadBId = Lw_Thread_Create("t_testb", tTestB, LW_NULL, LW_NULL);
if (hThreadBId == LW_OBJECT_HANDLE_INVALID) {
printf("t_testb create failed.\n");
return (-1);
}
Lw_Thread_Join(hThreadAId, LW_NULL);
Lw_Thread_Join(hThreadBId, LW_NULL);
return (0);
}
在 SylixOS Shell 下运行程序:
# ./Atomic
tTestA(): count = 0
tTestA(): count = 1
tTestA(): count = 2
tTestA(): count = 3
tTestA(): count = 4
tTestA(): count = 5
tTestA(): count = 6
......
# ts
NAME TID PID PRI STAT LOCK SAFE DELAY PAGEFAILS FPU CPU
------------------- ------- ----- --- ---- ---- ---- ---------- --------- --- ---
POSIX_Atomic_Weight 4010092 45 200 JOIN 0 0 1 USE 0
t_testa 4010093 45 200 SLP 0 922 0 0
t_testb 4010094 45 200 SLP 0 922 0 0