更新时机:没有CPU再去操作这段被RCU保护的临界区后,这段临界区即可回收了,此时回调函数即被调用 。
从实现逻辑来看,RCU锁在多个写者之间的同步开销还是比较大的,涉及到多份数据拷贝,回调函数等,因此这种锁机制的使用范围比较窄,适用于读多写少的情况,如网络路由表的查询更新、设备状态表更新等,在业务开发中使用不是很多 。
可重入锁和不可重入锁递归锁recursive mutex 可重入锁(reentrant mutex)非递归锁non-recursive mutex 不可重入锁(non-reentrant mutex)Windows下的Mutex和Critical Section是可递归的 。Linux下的pthread_mutex_t锁默认是非递归的 。
在Linux中可以显式设置PTHREAD_MUTEX_RECURSIVE属性,将pthread_mutex_t设为递归锁避免这种场景 。
同一个线程可以多次获取同一个递归锁,不会产生死锁 。而如果一个线程多次获取同一个非递归锁,则会产生死锁 。
如下代码对于非递归锁的死锁示例:
MutexLock mutex;voidtesta(){mutex.lock();do_sth();mutex.unlock();}voidtestb(){mutex.lock();testa();mutex.unlock();}代码中testb使用了mutex并且调用testa,但是testa中也调用了相同的mutext,这种场景下如果mutex是非递归的就会出现死锁 。
条件变量condition variables条件变量是用来等待线程而不是上锁的,通常和互斥锁一起使用 。互斥锁的一个明显的特点就是某些业务场景中无法借助系统来唤醒,仍然需要业务代码使用while来判断,这样效率本质上比较低 。
而条件变量通过允许线程阻塞和等待另一个线程发送信号来弥补互斥锁的不足,所以互斥锁和条件变量通常一起使用,来让条件变量异步唤醒阻塞的线程 。
条件变量和互斥锁的典型使用就是生产者和消费者模型,这个模型非常经典,也在面试中经常被问到,示例代码:
#include <stdio.h>#include <pthread.h>#define MAX 5pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;pthread_cond_t notfull = PTHREAD_COND_INITIALIZER;//是否队满pthread_cond_tnotempty=PTHREAD_COND_INITIALIZER;//是否队空int top = 0;int bottom = 0;void* produce(void* arg){int i;for ( i = 0; i < MAX*2; i++){pthread_mutex_lock(&mutex);while ((top+1)%MAX == bottom){printf("full! producer is waitingn");//等待队不满pthread_cond_wait(notfull,&mutex);}top=(top+1)%MAX;//发出队非空的消息pthread_cond_signal(notempty);pthread_mutex_unlock(&mutex);}return (void*)1;}void* consume(void* arg){int i;for ( i = 0; i < MAX*2; i++){pthread_mutex_lock(&mutex);while ( top%MAX == bottom){printf("empty! consumer is waitingn");//等待队不空pthread_cond_wait(notempty,&mutex);}bottom=(bottom+1)%MAX;//发出队不满的消息pthread_cond_signal(notfull);pthread_mutex_unlock(&mutex);}return (void*)2;}int main(int argc, char *argv[]){pthread_t thid1;pthread_t thid2;pthread_t thid3;pthread_t thid4;int ret1;int ret2;int ret3;int ret4;pthread_create(&thid1, NULL, produce, NULL);pthread_create(&thid2, NULL, consume, NULL);pthread_create(&thid3, NULL, produce, NULL);pthread_create(&thid4, NULL, consume, NULL);pthread_join(thid1, (void**)&ret1);pthread_join(thid2, (void**)&ret2);pthread_join(thid3, (void**)&ret3);pthread_join(thid4, (void**)&ret4);return 0;}其中pthread_cond_wait的使用是个需要注意的地方:
pthread_cond_wait()是先将互斥锁解开,并陷入阻塞,直到pthread_signal()发出信号后pthread_cond_wait()再加上锁,然后退出 。
以上关于本文的内容,仅作参考!温馨提示:如遇健康、疾病相关的问题,请您及时就医或请专业人士给予相关指导!
「四川龙网」www.sichuanlong.com小编还为您精选了以下内容,希望对您有所帮助:- 在运动健身之后消除疲劳的五个方法
- 提取json格式的数据 js中json字符串转json对象的方法
- 适合老年人练习的三个简单动作
- 运动小常识:登山时的健康步法
- 运动前人们常犯的几个热身错误
- 男人如何拥有挺拔的身材?
- 网络用语rs是什么意思 网络用语rs的意思
- 粉色百合花的花语和寓意 粉色百合花的花语介绍
- 吃鸡最高段位叫什么 吃鸡的相关知识
- 小米10青春版值得买吗,2021最值得买的手机推荐