并发基础 -- Linux 内核同步机制
来源:互联网 发布:淘宝网店首页图片 编辑:程序博客网 时间:2024/05/16 09:49
1 Linux 原子操作
通常用于linux内核的同步机制。所谓原子操作,就是该操作绝不会在执行完毕前被任何其他任务或事件打断,也就说,它的最小的执行单位,不可能有比它更小的执行单位。 在单处理系统中(UniProcessor)中,能够在单条指令中完成的操作都可以认为是"原子操作",因为中断只能发生于指令之间;在多处理系统中, 由于系统中有多个处理器在独立地运行,即使能在单条指令中完成的操作也有可能受到干扰。原子操作不可能由软件单独完成,需要硬件的支持,因此是架构相关的。其API和原子类型的定义都定义在内核源码树的include/asm/atomic.h文件中,它们都使用汇编语言实现,因为C语言并不能实现这样的操作。
原子操作主要用于实现资源计数,很多引用计数(refcnt)就是通过原子操作实现的。原子类型定义如下:
#ifdef CONFIG_SMP
#define LOCK "lock ; "
#else
#define LOCK ""
#endif
在x86的原子操作实现代码中,定义了LOCK宏,这个宏可以放在随后的内联汇编指令之前。如果是SMP,LOCK宏被扩展为lock指令;否则被定义为空--单CPU无需防止其它CPU的干扰,锁内存总线完全是在浪费时间。
typedef struct { volatile int counter; } atomic_t;
在所有支持的体系结构上原子类型atomic_t都保存一个int值。在x86的某些处理器上,由于工作方式的原因,原子类型能够保证的可用范围只有24位。volatile是一个类型描述符,要求编译器不要对其描述的对象作优化处理,对它的读写都需要从内存中访问。
几个原子操作的utiltiy函数:
(1) #define ATOMIC_INIT(i) { (i) } // 用于在定义原子变量时,初始化为指定的值
(2) #define atomic_read(v) ((v)->counter) // 读取v指向的原子变量的值。由于该操作本身就是原子的,只需要一次内存访问就能完成,因此定义为一个宏,并用C代码实现。
(3) #define atomic_set(v,i) (((v)->counter) = (i)) //设置v指向的原子变量为i
(4) static __inline__ void atomic_add(int i, atomic_t *v) //将v指向的原子变量加上i。
{
__asm__ __volatile__(
ATOMIC_SMP_LOCK "addl %1,%0"
:"=m" (v->counter)
:"ir" (i), "m" (v->counter));
}
实现中,使用了带有C/C++表达式的内联汇编代码,格式如下(参考《AT&T ASM Syntax》):
__asm__ __volatile__("Instruction List" : Output : Input : Clobber/Modify);
__asm__ __volatile__指示编译器原封不动保留表达式中的汇编指令系列,不要考虑优化处理。涉及的约束还包括:
1) 等号约束(=):只能用于输出操作表达式约束,说明括号内的左值表达式v->counter是write-only的。
2) 内存约束(m):表示使用不需要借助寄存器,直接使用内存方式进行输入或输出。
3) 立即数约束(i):表示输入表达式是一个立即数(整数),不需要借助任何寄存器。
4) 寄存器约束(r):表示使用一个通用寄存器,由GCC在%eax/%ax/%al、%ebx/%bx/%bl、%ecx/%cx/%cl和%edx/%dx/%dl中选取一个合适的。
(5) static __inline__ void atomic_sub(int i, atomic_t *v)
{
__asm__ __volatile__(
ATOMIC_SMP_LOCK "subl %1,%0"
:"=m" (v->counter)
:"ir" (i), "m" (v->counter));
}
(6) static __inline__ int atomic_inc_and_test(atomic_t *v)
{
unsigned char c;
__asm__ __volatile__(
ATOMIC_SMP_LOCK "incl %0; sete %1"
:"=m" (v->counter), "=qm" (c)
:"m" (v->counter) : "memory");
return c != 0;
}
(7) static __inline__ int atomic_add_negative(int i, atomic_t *v)
将v指向的原子变量加上i,并测试结果是否为负。若为负,返回真,否则返回假。这个操作用于实现semaphore。
自定义函数:
#define CAS(_a, _o, _n) /
({ __typeof__(_o) __o = _o; /
__asm__ __volatile__( /
"lock cmpxchg %3,%1" /
: "=a" (__o), "=m" (*(volatile unsigned int *)(_a)) /
: "0" (__o), "r" (_n) ); /
__o; /
})
cmpxchg : 将al,ax,eax,rax中的值与首操作数比较,如果相等,第2操作数的直装载到首操作数,zf置1。如果不等, 首操作数的值装载到al,ax,eax,rax并将zf清0。
应用场景:
原子操作通常用于实现资源的引用计数,在TCP/IP协议栈的IP碎片处理中,就使用了引用计数,碎片队列结构struct ipq描述了一个IP碎片,字段refcnt就是引用计数器,它的类型为atomic_t,当创建IP碎片时(在函数ip_frag_create中),使用atomic_set函数把它设置为1,当引用该IP碎片时,就使用函数atomic_inc把引用计数加1。
当不需要引用该IP碎片时,就使用函数ipq_put来释放该IP碎片,ipq_put使用函数atomic_dec_and_test把引用计数减1并判断引用计数是否为0,如果是就释放IP碎片。函数ipq_kill把IP碎片从ipq队列中删除,并把该删除的IP碎片的引用计数减1(通过使用函数atomic_dec实现)。
2 信号量(semaphore)
- 并发基础 -- Linux 内核同步机制
- Linux内核并发机制
- Linux 内核同步机制
- Linux 内核同步机制
- Linux内核 - 同步机制
- linux内核同步机制
- Linux 内核同步机制
- linux 内核同步机制
- Linux 内核同步机制
- Linux内核同步机制之(七):RCU基础
- Linux内核的同步机制
- Linux内核中的同步机制
- Linux内核的同步机制
- Linux内核的同步机制
- Linux内核的同步机制
- Linux内核的同步机制
- Linux内核的同步机制
- Linux内核的同步机制
- 读取DBF库数据
- 金发尤物的困惑
- 在线学习平台、微软应用程序商店
- 每天六个动作小肚子不见了
- SQL SERVER 2000中各表外键名,主键名的获取
- 并发基础 -- Linux 内核同步机制
- OICQ 99c版本加密方法研究报告
- 面对严峻的就业形式,我们该做些什么?
- msn无法登陆,错误代码:80072745解决方案
- mysql数据类型
- 查看锁信息
- 山村屠杀源与公共知识的运用
- spring 调用 tomcat5.5-6 resource
- Linux上的C/C++编译器gcc/egcs详解