案例代码:
运行截图:
原因分析 :
深入分析count++ , 将c代码转换汇编代码:
mov [count] , eax; // 将内存的count 移动到eax寄存器中
inc eax; // 将eax寄存器中的值自增一
mov eax,[count] // 将eax寄存器的值 mov 到count 中
正常情况:
不正常情况:
解决问题:
count 是一个临界 资源: 两个线程公用的一个变量
1、互斥锁 mutex: 执行count之前 加锁 ,执行count之后解锁,当一个线程检查到这个互斥锁 被占用的时候,那么这个线程会被让出CPU 会引起切换。
代码:
运行结果: 成功打印到一百万
原理: 在某一线程执行 count++ 时 其他线程进不来,将三条汇编指令变成一个代码整体, 其中代码整体中一条指令在运行,那么其他线程就会执行不了这个代码整体,就会阻塞等待。
2、自旋锁spinlock:用法基本和互斥锁一样,当另一个线程检查到这个自旋锁 被占用的时候,那么这个线程会while循环尝试获取锁。
代码:
运行结果:
自旋锁spinlock / 互斥锁mutex 区别和用途:
自旋锁:获取锁时相当于 while(1) 概念,尝试死循环重复获取锁,应用: 锁的内容很少。
互斥锁:当另一个线程检查到这个互斥锁 被占用的时候,这是这个线程会被让出CPU 会引起切换, 会引起线程切换等待,等待下一次被调用,应用:锁的内容比较多的时候,比如线程安全的rbtree
原子操作
单条cpu 指令实现,运行多条指令的运行(汇编代码实现)。
案例代码:
分析:
将: mov [count],eax
inc eax;
mov eax,[count]
这三条指令 变成 一条指令: xadd1 1,[count]
代码解析:
12行: 将 参数2(add) 加上 参数1(value) 最后赋值给 参数1(value)
总结:
1、自旋锁(spinlock): 锁占用时,其它线程while(1)循环尝试获取锁。
2、互斥锁(mutex):锁占用时,其它线程切除cpu不让运行。
3、原子操作(CAS): 将三条汇编指令变为一条。