线程同步与互斥

一、基本概念
(1)公共的资源称为临界资源;
(2)访问临界资源的代码称为临界区;
(3)互斥,为了保护临界区/临界资源的安全性;
(4)同步,访问临界资源时需要按照一定的顺序;
(5)原子性,对目标数据要么改了,要么没改,不存在改一部分的情况。
二、mutex(互斥量)
·大部分情况,线程使用的数据都是局部变量,变量的地址空间在线程栈
空间内,这种情况,变量归属单个线程,其他线程无法获得这种变量;
·有些情况,很多变量都需要在线程间共享,这样的变量称为共享变量,可以通过数据的共享,完成线程之间的交互;
·多个线程并发的操作共享某些变量,会带来一些问题;
·多个线程之间所定义的全局变量属于临界资源。

刚上面提到 多个线程并发的操作共享变量,会带来某些问题,如何解决这个问题:
(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  

·销毁互斥量
销毁互斥量需要注意的有:
·使用PTHREAD_MUTEX_INITIALIZER初始化的互斥量不需要销毁;
·不要销毁一个已经加锁的互斥量;
·已经销毁的互斥量,要确保后面不会有线程再尝试加锁。

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时,可能会遇到以下情况:
·互斥量处于未锁状态,该函数会将互斥量上锁,同时返回成功;
·发起函数调用时,其他线程已经锁定互斥量,或者其他线程同时申请互斥量,但没有竞争到互斥量,那么pthread_lock调用会陷入阻塞,等待互斥量解锁。
三、同步量
·条件变量
条件变量要使用时必须和互斥锁搭配起来。
一个线程可以通过条件变量来通知另一个线程某件事情是否发生;
为了实现同步功能;
·条件变量函数

初始化:
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:互斥量
唤醒等待:
唤醒多个条件变量
int pthread_cond_broadcast(pthread_coond_t *cond);

唤醒一个条件变量
int pthread_cond_signal(pthread_cond_t *cond);

简单案例:
生产者—–消费者模型(321);
在该模型中存在着321原则,具体理解为:在该模型中具有3种关系、2类角色、1个交易场所;
生产者与生产者:互斥关系;
消费者与消费者:互斥关系;
生产者与消费者:互斥且同步
四、POSIX信号量
POSIX信号量和SystemV信号量作用相同,都是用于同步操作,达到无冲突的访问共享资源的目的,但POSIX可以用于线程间同步。
·信号量本质上市一个临界资源,必须保证它是原子的;
·信号量本质上也是一个计数器,是用来描述临界资源的计数器;
·线程只要能够申请到信号量,那么临界资源中肯定有一份资源属于线程;
·申请信号量,进行P操作(减1),释放信号量,进行V操作(加1);PV操作必须保证信号量的原子性。

初始化信号量:
#include<semaphore.h>
int seem_init(sem_t *sem,int pshared,unsigned int value);
参数:
    pshared:0表示线程间共享,非零表示进程间共享
    value:信号量初始值
销毁信号量:
int sem_destroy(sem_t *sem);
等待信号量:
功能:等待信号量,会将信号量的值减1
int sem_wait(sem_t *sem);
发布信号量:
功能:发布信号量,表示资源使用完毕,可以归还资源了,将信号量值加1
int sem_post(sem_t *sem);

五、读写锁
·对于读写锁,写是互斥的,读是共享的,写锁的优先级高于读(即写者优先);
·读写锁的本质上是一把自旋锁(自旋锁不会被挂起);
·互斥量和信号量本质上是一种挂起等待锁。

读写锁接口

初始化:
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,const pthread_rwlockattr_t *restrict attr);
销毁:
int pthread_rwlock_ddestroy(pthread_rwlock_t *rwlock);
加锁和解锁:
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);  //读加锁
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);  //写加锁

int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

读者—-写者模型:

读者---读者:共享关系
写者---写者:互斥关系
读者---写者:同步且互斥

读者---写者模型与生产者---消费者模型区别的本质是:
   生产者---消费者模型中的消费者会将数据拿走,而读者---写者模型中没有。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值