Home 内核-atomic(原子变量)
Post
Cancel

内核-atomic(原子变量)

介绍

在Linux内核中,原子变量(atomic variables)是一种特殊类型的变量,可以在多线程或多核环境下进行原子操作。原子操作是一种不可中断的操作,要么完全执行,要么完全不执行,不存在中间状态。 原子变量通常用于实现同步机制,确保对共享数据的访问和修改在多线程环境下的正确性。它们提供了一组原子操作函数,可以以原子方式执行常见的操作,如读取、写入、递增、递减等,不需要额外的锁机制来保护。

原子变量,其实现和硬件密切相关,使用一些汇编指令保证变量操作的原子性,这在C语音层面是无法直接做到的。具体实现在不同的机器平台必然也有差异。linux内核提供了一些统一的操作接口。

使用原子变量不需要额外的锁机制就可以保证操作的原子性,它是无锁的,使用比较方便,而且轻量。主要限制就是,它仅支持简单的整型变量,对于复杂的结构体是不支持的,相关操作也是对整型变量的相关操作。

适用场景

  • 计数器:原子变量常用于实现计数器功能,例如统计某个事件发生的次数。
  • 标志位:原子变量可以用作标志位,在多线程环境下进行状态的检查和设置。
  • 简单的操作:对于简单的操作,如递增、递减、读取、写入等,原子变量是一种高效且线程安全的选择。
  • 轻量级同步:当需要进行轻量级的同步时,而不需要使用复杂的锁机制时,原子变量是一个合适的选择。它们可以用于避免竞态条件和数据访问冲突。

对于复杂的同步问题或需要进行一系列操作作为一个原子操作的场景,原子变量就不合适。

结构定义及相关API

Linux内核中,原子变量的定义在内核源码头文件/include/linux/types.h中,它们以atomic_t类型表示。 结构定义非常简单,就是int或int64,其实现主要靠应用机器架构的汇编实现的。

1
2
3
4
5
6
7
8
9
typedef struct {
	int counter;
} atomic_t;

#ifdef CONFIG_64BIT
typedef struct {
	s64 counter;
} atomic64_t;
#endif

以下是一些常用的原子操作函数:相关操作需要包含头文件/include/linux/atomic.h, 操作包括加,减,自增,自减,与,或,异或等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//常规32bit 接口
atomic_set(atomic_t *v, int i); //v = i,可以用于初始化
atomic_read(const atomic_t *v); //将原子变量的值读取出来
atomic_inc(atomic_t *v);    //v值递增1。
atomic_dec(atomic_t *v);    //v值递减1。
atomic_add(int i, atomic_t *v); // v = v + i
atomic_sub(int i, atomic_t *v); // v = v - i
atomic_and(int i, atomic_t *v); // v = v & i
atomic_or(int i, atomic_t *v);  // v = v | i
atomic_xor(int i, atomic_t *v); // v = v ^ i
atomic_xchg(int i, atomic_t *v);    //以原子方式将原子变量v的值交换为整数值i,并返回之前v的值
atomic_cmpxchg(int old, int new, atomic_t *v);  //以原子方式比较原子变量v的值与整数值old,如果相等则将其更新为整数值new。

//64bit 接口
atomic64_set(atomic64_t *v, s64 i);
atomic64_read(const atomic64_t *v);
atomic64_inc(atomic64_t *v);
...

还有其他一些合并后的,如atomic_add_return等,把两步合起来,优化性能。总之,操作接口比较多。 另外,在64位机器上,有64位版本的atomic,即atomic64_t,对64位的atomic操作需要使用对应的API,和32位的int是分开的两套接口,不过基本相同。

This post is licensed under CC BY 4.0 by the author.

内核-RCU

内核-perCPU(perCPU变量)