linux线程同步

线程同步的四种方法

互斥量(锁mutex)
读写锁(写互斥,读共享)
条件变量
信号量

1、概念

对于某一个资源或功能函数,多线程不能共同访问,共同执行。只能依次等待执行。即cpu时间片不可分割。

2、互斥量

pthread_mutex_init(pthread_mutex_t *,pthread_mutexattr *属性)初始化互斥量(锁)。pthread_mutex_t只有两种取值,1表示 上锁状态。0表示解锁状态。
pthread_mutex_lock()加锁,对mutex加锁之后,其值变为1。再调用pthread_mutex_lock对其加锁,会阻塞等待,直至mutex被解锁变为0后,才被加锁再次变为1;
pthread_mutex_unlock()解锁
pthread_mutex_destory(pthread_muex_t mutex)销毁锁

3、原子操作

对于一个变量进行赋值,–,++操作,可以分成三个步骤,读寄存器,操作,写入寄存器。因此。多线程编程注意如果不加锁,即使只进行最简单的变量操作,变量也会出问题。可以使用atomic将变量变为原子操作,即针对这个变量的操作是不可分的。
#include

4、死锁

使用一把锁死锁:
pthread_lock();
解决办法:仔细检查代码,即可避免,在加锁之前先检查是否可以加锁。
pthread_lock();对同一把加锁两次会造成死锁。
两个函数中使用两把锁死锁:
void a(pthread_mutex t1,pthread_mutex t2){
pthread_lock(t1);
pthread_lock(t2);
}
void b(pthread_mutex t1,pthread_mutex t2){
pthread_lock(t2);
pthread_lock(t1);
}
两个函数中对两把锁加锁顺序不一致,会造成死锁。互相等待。
解决办法:加锁顺序一致即可避免,或者也可以使用trylock函数,如果加锁失败则释放已有的锁,牺牲自己成全别的线程。

在分布式锁中,如果一个机器拿到锁只后,还没有释放锁直接宕机了,也会造成死锁。
可以对分布式锁加上过期时间,到了时间自动释放。

5、条件变量pthread_cond

条件变量可以看成是pthread_mutex锁的一层封装,更方便于多线程同步。条件变量的作用就在于生产者消费者模型。
pthread_cond_init(pthread_cond_t t 传出一个pthread_cond_t,pthread_cond_attr 设置属性,可以传null)
pthread_cond_wait(pthread_cond_t 条件变量,pthread_mutex_t 使用那把锁进行同步)。再使用pthread_cond_wait之前,一定要先加锁,才能把锁传入pthread_cond_wait。
pthread_cond_signal(pthread_cond_t *)这个条件变量已经满足(但是只通知给一个线程)
pthread_cond_broadcast()通知所有等待此条件变量的线程
函数内部
1、将传入的pthread_mutex_t解锁,pthread_cond_signal才能访问pthread_cond_t。
2、阻塞等待条件被满足、在执行pthread_lock(),对pthread_mutex_t加锁。
函数内部为原子操作。
为什么pthread_cond_wait之前一定要先加锁?
因为有可能pthread_cond_wait还没执行完,切换到另外一个线程,执行了pthread_cond_singal,而这时pthread_cond_wait还没准备好,就错过了条件变量的唤醒,从而造成错误。pthread_cond_wait和pthread_cond_signal都是访问pthread_cond_t个共享资源,所以要加锁。

而且我们希望先pthread_cond_wait,再pthread_cond_signal,否则先唤醒在等待毫无用处,pthread_cond_wait已经错过了唤醒就会一直阻塞。

注意

pthread_cond_wait(0条件变量满足之后,会加锁,因此对共享资源操作结束后,需要手动解锁pthread_mutex_unlock();

6、生产者消费者模型

锁实现:
全局变量count代表仓库有多个产品
线程1:不断地生产产品,每1s,count++,
线程2:不断消耗产品,如果count!=0,count–
线程3:不断消耗产品,如果count!=0,count–
count是全局变量,所以要加锁,多个线程互相竞争,谁先拿到锁,谁执行,其他的等待。
但是线程1一直不生产count=0,其他消费者竞争到锁也没用,浪费cpu资源。因而提出使用条件变量
条件变量实现:
消费者线程内,如果count==0,使用pthread_cond_wait(),等待生产者唤醒。生产者生产仓储产品后,使用pthread_cond_broadcst()或pthread_cond_singal()唤醒消费者。

7、信号量

线程之间的同步也可借助于信号量来实现
类似于锁,加锁pthread_mutex_t 就–,如过本来就是0,再减减就会线程阻塞。解锁++变为1
信号量和锁的区别在于信号量可以从0到val取值,从val减减到0,再减减就会线程阻塞。而锁只有两个取值。
即锁同一时间只能有一个线程操作。而信号量可以同让val个线程继续向下执行。
因此信号量并不具备保护共享资源的功能,信号量一般和互斥量同时使用
sem_init(sem_t *传出参数,0,int count);初始化一个信号量个数为count
sem_wait(sem_t *)sem_t减减操作,信号量减一
sem_post(sem_t *t)sem_t加加操作,信号量加一

9、自旋锁

自旋锁和互斥量唯一的区别就是:
线程没有拿到互斥量就会被挂起,知道竞争重新获取cpu资源,再尝试拿锁;
而线程如果拿到自旋锁,线程也不会释放cpu资源,而是一直霸占,一直尝试拿锁,知道拿锁成功,再继续往下执行。
自旋锁一般只在linux内核中使用。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值