linux之自旋锁
常见的各种锁
悲观锁:在每次取数据时,总是担心数据会被其他线程修改,所以会在取数据前先加锁(读锁,写锁,行锁等),当其他线程想要访问数据时,被阻塞挂起。
总是先行认为数据一定会被修改!所以要先加锁!保证没有人能够访问它!
==我们学的同步互斥机制!其实都是属于悲观锁的范畴!==
乐观锁:每次取数据时候,总是乐观的认为数据不会被其他线程修改,因此不上锁。但是在更新数据前,会判断其他数据在更新前有没有对数据进行修改。主要采用两种方式:版本号机制和CAS操作。
CAS操作:当需要更新数据时,判断当前内存值和之前取得的值是否相等。如果相等则用新值更新。若不等则失败,失败则重试,一般是一个自旋的过程,即不断重试。
这个在java更加的常见!
自旋锁,公平锁,非公平锁?
自旋锁(修改)
像是互斥锁,信号量,当我们申请失败了!那么进程在系统级别上就会被挂起——这种我们一般都称之为挂起等待锁
对于临界资源,我们可以加锁保护!然后对临界资源进行区域性的使用!——例如:环形队列!
为了能够理解自旋锁我们先举个例子
有一天小明去找小王玩,到小王家楼下,小明就给小王打电话,叫小王出去一起玩!
但是小王说他要做作业,要等等!小明说那可以!小明于是就在楼下等起来了!小明等了好一会,但是小王还没有下了,于是小明又打电话,小王说还要等等,小明是一个急性子,于是每等一会就要给小王打电话!最后小王终于好了!然后一起去玩了
小明和小王玩的很开心,于是小明隔天又来找小王玩!小明到了之后给小王打电话!但是小王说他又在写作业!小明他想到昨天等了那么久!所以今天不想等了!于是小明说,他先去隔壁的网吧玩!你写作业快好了就给他提前打个电话!他就再去楼下等他!
小王觉得也挺好的!省的小明一直给他打电话!小明玩着玩着,小王给他打电话!这时候,小明就回去了去楼下等,此时小王很快就下来了!
在故事当中,第二天,小明给小王打电话!小明觉得等着很久,于是不等了,打算去网吧做自己的事情!——==翻译过来就是当前的线程,去尝试的申请锁!发现上一个线程要在临界资源里待了很久,所以不打算等!所以将自己挂起!(从楼下到网吧这就是挂起的过程,葱网吧到楼下就是唤醒的过程!)==——这就是一种挂起等待的过程!
在故事中!第一题小明去找小王!小明向小王打电话!好了没?没有就挂电话!直到好之前,一直循环这个过程!——==即一个线程,不断的向另一个线程询问是否就绪!这种状态就是自旋!(自旋的过程就是轮询的过程!)==
==那么是什么决定了最终的等待方式?==
假如小王说,我1分钟后就下来,小明打电话说,我先去网吧,要下来了再打我电话合适吗?!——不合适!保不定还没有到小王就到楼下了!
那么小王说,1小时后再下来!那么此时去网吧等待就合适了!小明一直给小王打电话!反倒会影响的效率!
==所以决定了最终的等待方式的问题其实是——我们要等待的时长的问题!==
们以前研究过,如何整体访问临界资源!如何部分访问临界资源!如何加锁!——但是我们从来没有研究已经申请过锁的线程去访问这个共享资源需要多长时间!——即已经被申请的临界资源,决定了其他线程就要等待!
==一个成功申请临界资源的线程,在临界区内要待多长时间!就直接决定了我们使用的的是挂起等待锁,还是自旋!==
如果时间长——那么就挂起等待!如果时间短那么就——自选(轮询)
修改
如何评估线程待在临界区时间长短!
在代码层面我们去理解是很难有一个结论的!——重点是要结合场景!
==但是一般来说——当临界区里面有高复杂度的计算!IO操作,等待某转软件条件!大概率是要挂起等待的!==
==如果临界区里面!仅仅是一个简单的内存操作!一些代码很短,执行速度很快的代码我们就可以采用自旋锁!==
**不过自旋我们一般很少会去使用!因为虽然自选在==正确的评估时间长短的情况下==确实是比挂起等待更快!——==但是一旦评估出错!就会大量的消耗CPU资源!==**而且如果是在挂起等待的时候出现死锁!那么无非就是两个线程互相阻塞!但是一般自旋锁里面出现了类似死锁的情况!所有的执行流都会疯狂的自旋检测锁的状态!没有人去释放锁!那么就有可能会让我们的CPU瞬间就被打满!==所以自旋锁是有危险的!大部分没有特殊要求的情况下,或者及其确定使用自旋锁不会出问题且场合十分适合自旋!都是推荐使用挂起等待!==
因为评估在临界资源的长短是由程序员来决定的!使用那个方案也是由程序员来决定的!所以当如果我们真的不确定!我们可以选择都用一次!分别测试一下!那个效率高用那个!
一般系统层面代码使用的自旋锁更多!用户层面使用的会少一些
自旋锁的接口
标签:小明,小王,二千,linux,临界,线程,自旋,字长,等待 From: https://blog.51cto.com/u_15835985/9452263
初始化接口
pthread_spinlock_t,这个就是自旋锁的类型!
pshared参数是表示共享级别!0表示线程间不共享!非0就是表示与其他线程共享!
加锁接口
自旋的过程是不用我们自己做的!
想要自己做也是可以的!——使用try_lock如果申请失败就可以自己去实现
解锁接口
无论是挂起等待还是自旋!——正在别的线程看来其实都是在等待!
==用法其实和互斥锁是一样的!==