mutex 与 CAS
来源:互联网 发布:windows解压war包 编辑:程序博客网 时间:2024/06/06 18:43
CAS: compare and swap
CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值。否则,处理器不做任何操作。无论哪种情况,它都会在 CAS 指令之前返回该位置的值。(在 CAS 的一些特殊情况下将仅返回 CAS 是否成功,而不提取当前值。)CAS 有效地说明了“我认为位置 V 应该包含值 A;如果包含该值,则将 B 放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可。”
template <class T> bool CAS(T* addr, T expected, T value) { if (*addr == expected) { *addr = value; return true; } return false; }
mutex的一种实现cas
bool i = 0;//1表示锁住lock(){ cas(i, 0, 1)}unlock(){ cas(i, 1, 0);}
mutex的一种实现sac(sac是这样叫的吗?我自己想的)
首先要知道,每个线程都有它自己的一组CPU寄存器,称为线程的上下文。该上下文反映了线程上次运行时该线程的CPU寄存器的状态。
假设Mutex变量的值为1表示互斥锁空闲,这时某个进程调用lock可以获得锁,而Mutex的值为0表示互斥锁已经被某个线程获得,其它线程再调用lock只能挂起等待。那么lock和unlock的伪代码如下:
mutex = 0;lock: movb $1, %al xchgb %al, mutex if(al寄存器的内容 == 0){ return 0; } else 挂起等待; goto lock; unlock: movb $0, mutex 唤醒等待Mutex的线程; return 0;
想起来std::atomic类模版中有这样一个成员函数exchange(),跟这个有点相似,把它包装一下就可以实现一个mutex(因为exchange可以保证在任意时刻,atomic中的数只有一个线程能得到)。
// 给它起个名叫1000000米赛跑#include <iostream> // std::cout#include <atomic> // std::atomic#include <thread> // std::thread#include <vector> // std::vectorstd::atomic<bool> ready (false);std::atomic<bool> winner (false);void count1m (int id) { while (!ready) {} // wait for the ready signal for (int i=0; i<1000000; ++i) {} // go!, count to 1 million if (!winner.exchange(true)) { std::cout << "thread #" << id << " won!\n"; }};int main (){ std::vector<std::thread> threads; std::cout << "spawning 10 threads that count to 1 million...\n"; for (int i=1; i<=10; ++i) threads.push_back(std::thread(count1m,i)); ready = true; for (auto& th : threads) th.join(); return 0;}
http://www.cplusplus.com/reference/atomic/atomic/exchange/
貌似现在的mutex有优化?lock会首先在应用层上检测冲突,如果有冲突也会继续try几次,如果还无法取得锁才陷入休眠状态。
关于自旋锁:
自旋锁,当无法获得锁时,不会陷入内核休眠,而是执行空循环。最好的情况应该是 拥有锁的线程要很快执行完,即等待线程空循环等待的时间小于线程切换的时间,否则自旋锁没有任何优势。
尤其是,假设并发稍微多点,线程1在lock之后unlock之前发生了时钟中断,一段时间后才会被切回来调用unlock,那么这段时间中另一个调用lock的线程就得空跑while了。这才是最浪费cpu时间的地方。
内核的话,可以开关中断,可以让持有锁的线程不切换出去,从而尽快的执行完,所以自旋锁适合在内核某一些情况下使用;如果在用户态使用,那么结果的好坏就要依靠操作系统的线程调度了,有点“靠天吃饭”的感觉。
关于递归锁:
看着很有意义,但是建议是不去用。recursive mutex 可能会隐藏代码里的一些问题。典型情况是你以为拿到一个锁就能修改对象了,没想到外层代码已经拿到了锁,正在修改(或读取)同一个对象呢。http://blog.csdn.net/Solstice/article/details/5307710#_Toc2810
而用普通锁则不会发生这种暗地里偷偷修改的事情,它会死锁,提醒你修改自己的函数逻辑。
- mutex 与 CAS
- CAS锁与MUTEX锁性能测试
- std::mutex与pthread mutex区别
- pthread_cond_wait与mutex、while
- semaphore与Mutex
- semaphore与Mutex
- mutex 与 WaitForSingleObject
- 探讨mutex与semaphore
- semaphore与Mutex
- Semaphore与Mutex简介
- Semaphore与Mutex
- Spin lock 与mutex
- spinlock与mutex对比
- mutex与spinlock
- Semaphore与Mutex
- mutex与semaphore的区别
- Mutex与Critical Section比较
- mutex与semaphore的区别
- (poj 2449 Remmarguts' Date)<A*-K短路模板>
- HDU
- HDU
- SPSS--独立样本t检验与配对样本t检验
- C#整体总结
- mutex 与 CAS
- poj 2109
- dp day3/4-二维dp
- 关于思想无限的一点思考
- Arduino W5100 Yeelink PIN7控制
- hdu 6154
- 【学姐的胡策】训练8.18(KMP+dp)
- 第3篇 中国近现代史纲要(二)
- HDU