原子量

更新时间:
2024-01-09
下载文档

原子量

在本章的开篇我们介绍了变量 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
文档内容是否对您有所帮助?
有帮助
没帮助