原子量操作
原子量操作 是不可被打断的一个或一系列操作。
当我们的程序存在较多对变量的互斥访问时,我们的程序必然存在较多的锁和锁操作,一方面这使得我们的程序难以编写和维护,另一方面不合理的锁操作可能会发生死锁。
为了避免这些问题,SylixOS 提供了原子量类型 atomic_t 及其 API,原子量类型可储存一个整型 INT 类型的值,同时使用原子量 API 对原子量进行的操作是一个原子操作,因为原子操作不可打断,这样在设备驱动的并发操作中也就不会存在混乱风险。
SylixOS 原子量的类型为 atomic_t。使用时需定义一个 atomic_t 类型的变量,如:
atomic_t atomic;
原子量
原子量的设置和获取
#include <SylixOS.h>
VOID API_AtomicSet (INT iVal, atomic_t *patomic);
函数 API_AtomicSet 原型分析:
- 参数 iVal 是需要设置的值。
- 参数 patomic 是原子量的指针。
#include <SylixOS.h>
INT API_AtomicGet (atomic_t *patomic);
函数 API_ AtomicGet 原型分析:
- 此函数成功时返回原子量的值,失败时返回 PX_ERROR 并设置错误号。
- 参数 patomic 是原子量的指针。
原子量的加和减
#include <SylixOS.h>
INT API_AtomicAdd (INT iVal, atomic_t *patomic);
函数 API_ AtomicAdd 原型分析:
- 此函数成功时返回原子量的新值,失败时返回 PX_ERROR 并设置错误号。
- 参数 iVal 是需要加上的值。
- 参数 patomic 是原子量的指针。
#include <SylixOS.h>
INT API_AtomicSub (INT iVal, atomic_t *patomic);
函数 API_ AtomicSub 原型分析:
- 此函数成功时返回原子量的新值,失败时返回 PX_ERROR 并设置错误号。
- 参数 iVal 是需要减去的值。
- 参数 patomic 是原子量的指针。
原子量的自增和自减
#include <SylixOS.h>
INT API_AtomicInc (atomic_t *patomic);
INT API_AtomicDec (atomic_t *patomic);
以上两个函数原型分析:
- 此函数成功时返回原子量的新值,失败时返回 PX_ERROR 并设置错误号。
- 参数 patomic 是原子量的指针。
原子量的逻辑位操作
#include <SylixOS.h>
INT API_AtomicAnd (INT iVal, atomic_t *patomic);
函数 API_ AtomicAnd 原型分析:
- 此函数成功时返回原子量的新值,失败时返回 PX_ERROR 并设置错误号。
- 参数 iVal 是需要进行逻辑位与操作的值。
- 参数 patomic 是原子量的指针。
#include <SylixOS.h>
INT API_AtomicNand (INT iVal, atomic_t *patomic);
函数 API_ AtomicNand 原型分析:
- 此函数成功时返回原子量的新值,失败时返回 PX_ERROR 并设置错误号。
- 参数 iVal 是需要进行逻辑位与非操作的值。
- 参数 patomic 是原子量的指针。
#include <SylixOS.h>
INT API_AtomicOr (INT iVal, atomic_t *patomic);
函数 API_ AtomicOr 原型分析:
- 此函数成功时返回原子量的新值,失败时返回 PX_ERROR 并设置错误号。
- 参数 iVal 是需要进行逻辑位或操作的值。
- 参数 patomic 是原子量的指针。
#include <SylixOS.h>
INT API_AtomicXor (INT iVal, atomic_t *patomic);
函数 API_ AtomicXor 原型分析:
- 此函数成功时返回原子量的新值,失败时返回 PX_ERROR 并设置错误号。
- 参数 iVal 是需要进行逻辑位异或操作的值。
- 参数 patomic 是原子量的指针。
原子量的交换操作
#include <SylixOS.h>
INT API_AtomicSwp (INT iVal, atomic_t *patomic);
函数 API_ AtomicSwp 原型分析:
- 此函数成功时返回原子量的旧值(进行操作前的值),失败时返回 PX_ERROR 并设置错误号。
- 参数 iVal 是需要设置的值。
- 参数 patomic 是原子量的指针。
以下程序展示了 SylixOS 原子量的使用,内核模块在装载时创建两个线程,两个线程分别对原子量 _G_atomicCount 进行自增操作和打印,内核模块在卸载时删除两个线程。
#define __SYLIXOS_KERNEL
#include <SylixOS.h>
#include <module.h>
LW_HANDLE _G_hThreadAId = LW_OBJECT_HANDLE_INVALID;
LW_HANDLE _G_hThreadBId = LW_OBJECT_HANDLE_INVALID;
static atomic_t _G_atomicCount;
static PVOID tTestA (PVOID pvArg)
{
while (1) {
printk("tTestA(): count = %d\n", API_AtomicGet(&_G_atomicCount));
API_TimeSSleep(1);
}
return (LW_NULL);
}
static PVOID tTestB (PVOID pvArg)
{
while (1) {
API_AtomicInc(&_G_atomicCount);
API_TimeSSleep(1);
}
return (LW_NULL);
}
VOID module_init (VOID)
{
printk("atomic_module init!\n");
_G_hThreadAId = API_ThreadCreate("t_testa", tTestA, LW_NULL, LW_NULL);
if (_G_hThreadAId == LW_OBJECT_HANDLE_INVALID) {
printk("t_testa create failed.\n");
return;
}
_G_hThreadBId = API_ThreadCreate("t_testb", tTestB, LW_NULL, LW_NULL);
if (_G_hThreadBId == LW_OBJECT_HANDLE_INVALID) {
printk("t_testb create failed.\n");
return;
}
}
VOID module_exit (VOID)
{
if (_G_hThreadAId != LW_OBJECT_HANDLE_INVALID) {
API_ThreadDelete(&_G_hThreadAId, LW_NULL);
}
if (_G_hThreadBId != LW_OBJECT_HANDLE_INVALID) {
API_ThreadDelete(&_G_hThreadBId, LW_NULL);
}
printk("atomic_module exit!\n");
}
在 SylixOS Shell 下装载模块:
#insmod ./atomic.ko
atomic_module init!
module atomic.ko register ok, handle: 0x13338f0
tTestA(): count = 0
tTestA(): count = 1
tTestA(): count = 2
tTestA(): count = 3
tTestA(): count = 4
在 SylixOS Shell 下卸载模块:
#rmmod atomic.ko
atomic_module exit!
module /lib/modules/atomic.ko unregister ok.