Linux (十二)线程同步于互斥

线程的同步与互斥

mutex(互斥量)
大部分情况,线程使用的数据是局部变量,变量的地址空间在线程栈空间内,这种情况,变量附属单个线程,其他线程无法获得这种变量。
但有时候,很多变量都需要在线程间共享,这样的变量称为共享变量,可以通过数据的共享,完成线程之间的交互
多个线程并发的操作共享变量,会带来一些问题。

这里写图片描述
这里写图片描述

这个时候我们会发现问题,票数会出现负数,因为操作不是原子的,而是对应三条汇编指令:
load:将共享变量ticket从内存加载到寄存器中
update:更新寄存器里面的值,执行-1操作
store:将新值从寄存器写回共享变量ticket的内存地址

所以要解决以上问题,需要做到三点
1:代码必须有互斥行为:当代码进入临界区执行时,不允许其他线程进入该临界区。
2:当临界区没有线程执行的时候,那么只能允许一个线程进入临界区
3:如果线程不在临界区中执行,那么该线程就不能阻止其他线程进入临界区

所以我们要做到以上三点,就需要一把锁。它的名字就叫做互斥量

互斥量的接口

初始化互斥量
初始化互斥量有两只方法
1:静态分配
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER

2:动态分配
int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
参数:
    mutex:要初始化的互斥量
    attr:NULL
销毁互斥量
销毁互斥量的时候要注意
使用静态分配方法初始化的互斥量不需要销毁。
不要销毁一个已经加锁的互斥量,
已经销毁的互斥量,要确保后面不会有线程尝试加锁

int pthread_mutex_destroy(pthread_mutex_t *mutex);
互斥量的加锁和解锁
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
返回值:成功返回0;失败返回错误号

如果在遇到其他线程已经锁定了互斥量,或因其他线程同时申请互斥量,但是没有竞争到互斥量,那么pthread_lock调用会陷入阻塞,等待互斥量解锁。

下面我们加上互斥量之后再来看看买票会不会出现问题
这里写图片描述
我们在共享变量ticket后面定义了互斥量,在线程进入操作的时候加锁,操作完成后解锁。还包括初始化互斥量,销毁互斥量。
这里写图片描述
此时我们就可以发现,售
票没有一点问题

条件变量

上面我们说的互斥量在加锁后只允许同一时间只有一个线程访问临界资源,其他线程没有申请到锁就无法访问临界资源。
那么,问题来了。。
假如两个线程,一个线程是拿资源的,一个线程是放置资源的,但是由于拿资源的线程优先级比较高,就会出现,拿资源线程一直申请锁,看没有资源,又释放锁,释放锁后又申请锁,周而复始,因为它的优先级比较高。所以使得放资源的线程都没有机会放置资源,这样就会产生线程死锁问题,
这个时候我们就必须引入条件变量来解决这个问题
条件变量在我们申请锁之后,发现没有资源就释放锁,并挂起等待,直到放资源的线程申请到锁,放置资源后,唤醒挂起等待的线程,通知它拿资源,这样就可以避免线程死锁。

条件变量函数

初始化
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr)
参数:
    cond:要初始化的条件变量
    attr:NULL
销毁
int pthread_cond_destroy(pthread_cond_t *cond)
等待条件满足
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
参数:
    cond:要在这个条件变量上等待
    mutex:互斥量

为什么pthread_cond_wait需要互斥量?
* 条件等待是线程间同步的一种手段,如果只有一个线程,条件不满足,一直等待下去也不会满足,所以必须要有一个线程通过某些操作,改变共享变量,使原先不满足的条件变得满足,并且有好的通知等待在条件变量上的线程
* 条件不会无缘无故变得满足,一定会涉及到共享数据的变化,所以一定要用互斥锁来保护,没有互斥锁就无法安全的获取和修改共享数据

唤醒等待
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);

猜你喜欢

转载自blog.csdn.net/mignatian/article/details/80083481