c语言 原子 字符串,C语言--原子操作

说完了进程的调度,就可以说下C语言的原子操作了。

原子操作,就是在执行的过程中、不会导致对数据的并发访问的、最小操作。

原子操作,是实现锁机制的基础。mutex,spinlock等,在其底层都有一个关键的原子操作。

原子操作的实现,需要CPU指令的支持,例如x86上的xchg/cmpxchg,ARM上的ldrex/strex。

最简单的原子操作,就是交换一个寄存器和一个内存地址的值。

typedef struct {

volatile int count;

} atomic_t;

static inline int atomic_xchg(atomic_t* v, int i)

{

int ret;

asm volatile(

"xchgl %0, %1"

:"=r"(ret)

:"m"(v->count),"0"(i)

);

return ret;

}

上面函数的功能,就是用值i去交换v->count的值,把交换到的值写到ret变量里,并返回。

根据这个函数,可以实现一个最简单的锁,锁的数据结构就是atomic_t,加锁函数如下:

void mutex_lock(atomic_t* v)

{

while (1 == atomic_xchg(v, 1)) {

sched_yield(); //获取锁失败后,放弃CPU

}

}

解锁函数如下:

void mutex_unlock(atomic_t* v)

{

v->count = 0;

}

v->count为1代表锁定,0代表没锁定,初始状态为0。

用1去交换v->count,如果返回0,则表示锁定成功,此时v->count为1。

如果返回1,则代表锁已经是锁定状态,本次获取锁失败,则放弃CPU并尝试继续获取锁,直到成功。

在锁定状态下,试图去获取锁,因为用1去交换,交换后v->count的值还是1,不会改变锁的状态。

以上需要CPU的指令xchg的原子性来保证。cmpxchg可以实现更复杂的原子操作。

如果是原子加或者减,则使用lock指令来锁定内存总线,然后执行add/sub指令。

atomic_dec_and_test原子操作,即减少引用计数并判断是否为0,在自动垃圾回收机制(GC)中经常用到,例如C++中的智能指针,java、Python等语言中的GC机制。

该函数的实现大概如下:

int atomic_dec_and_test(atomic_t* v)

{

char ret;

asm volatile(

"lock;decl %1\r\n" #锁定内存总线,并把v->count减1,该指令同时会设置EFLAGS

"sete %0" #把EFLAGS的零标志写到ret变量里,如果零标志被设置,则ret为1,否则0

:"r"(ret)

:"m"(v->count)

);

return ret;

}

也就是说,如果引用计数被减到0时,atomic_dec_and_test返回1,否则返回0。

如果某个带引用计数的对象,创建时引用计数设置为1,每次被引用时计数加1,释放时计数减1,当计数减少到0时,释放该对象的内存,就可以保证对象内存的正确释放了。

当然,在C++中,你故意(无意)多delete一次对象的指针,程序还是会崩的。

所以,高司令大神在java里直接不让delete了。只管new就行,什么时候delete交给高司令大神处理。

最后,lock机制是保证其下一条指令的内存操作是原子的,而再下一条就不归它管了。

sete指令之所以能正确工作,在于:

即使lock decl之后、sete之前发生了进程调度,内核也会保证切换回来时,EFLAGS的状态仍然是之前的状态。

所以,sete这条语句已经不需要原子性了。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值