c语言原子锁能保证多核线程安全吗,多线程加锁的核心原理

不管是Java还是C,都会遇到多线程数据同步的问题。一种解决数据因为多线程访问导致出错的方案就是使用锁。

通过Java的字节码或者C程序的汇编指令看,我们编写的语句,都是由多个机器指令完成的,所以会出现多个线程在CPU执行指令顺序无法预测,从而导致对数据处理结果会出错。那如果涉及多线程数据同步的语句都是单指令的,是否可以保证不出问题呢?对于单核CPU是可以保证的。同样,如果可以保证涉及多线程数据同步的语句都是原子操作,那也单核CPU可以保证数据同步是正常的。

以C语言为例,为实现多核CPU也能保证操作数据的同步性,加入了锁。我们在代码中,在处理的语句前先获取锁,处理完成后再释放锁。这样,在锁被占有时,请求获取锁的其他进程就只能干巴巴得等待,等只有锁的进程处理完后获取到锁才能进行操作。这样,多个进程对数据的处理就有了个先来后到,大家按顺序有条不紊得修改数据。

那锁是怎么实现呢?(锁的实现内容摘抄自《Linux C 编程一站式学习》)

可以假设一个变量mutex,变量的值为1表示锁空闲,可以获取;值为0表示锁已经被某个线程获得,其它线程再调用lock只能挂起等待。lock为获取锁方法,unlock为解锁方法:

lock:

if(mutex > 0){

mutex = 0;

return 0;

} else

挂起等待;

goto lock;

unlock:

mutex = 1;

唤醒等待Mutex的线程;

return 0;

“  细心的读者应该已经看出问题了:对Mutex变量的读取、判断和修改不是原子操作。如果两个线程同时调用lock,这时mutex是1,两个线程都判断mutex>0成立,然后其中一个线程置mutex=0,而另一个线程并不知道这一情况,也置mutex=0,于是两个线程都以为自己获得了锁。 ”

“ 为了实现互斥锁操作,大多数体系结构都提供了swap或exchange指令,该指令的作用是把寄存器和内存单元的数据相交换,由于只有一条指令,保证了原子性 ”

多核CPU,在不同CPU核上并行跑两个线程,同时对内存上的数据进行交换不还是会出问题吗?假设我不考虑CPU核cache,我们处理数据直接对内存进行操作,那么:

“  即使是多处理器平台,访问内存的总线周期也有先后,一个处理器上的交换指令执行时另一个处理器的交换指令只能等待总线周期。” -----《Linux C 编程一站式学习》

“ 目前的x86/x64的多核/多处理器系统是SMP结构,共享主存,内存是共享设备,多个处理器/核心要访问内存,首先要获得内存总线的控制权,任何时刻只有一个处理器/核心能获得内存总线的控制权,所以单就内存来说,不会出现多个处理器/核心同时访问一个内存地址的情况。” ----- https://blog.csdn.net/kekefen01/article/details/103072120

从上面分析可以了解, CPU上的交换指令只能一条一条得来,访问内存的总线对于CPU来说就是一根独木桥。

1b18c43256f3812cffc0d17fa403b995.png

【图片来源:https://www.cnblogs.com/Ligo-Z/p/13228056.html】

再看考虑cpu cache的情况:

“ 但是每个处理器/核心可能有自己的cache(非共享的),所以,如果某个内存地址的数据在多个处理器/核心的cache中都存在的话,是可能出现并发读的情况,对于读写,或者写写的并发操作,处理器实现的cache一致性协议可以保证物理上不会出现真正的并发操作。” ----- https://blog.csdn.net/kekefen01/article/details/103072120

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值