线程安全

一、线程安全

1、概念:多个执行流对临界资源进行争抢访问,而不会造成数据二义或者逻辑混乱;称这段争抢访问的过程是线程安全的;线程安全的
2、实现:如何保证多个执行流对临界资源进行争抢访问而不会造成数据二义
3、同步:通过条件判断,实现对临界资源访问的时序合理性
4、互斥:通过唯一访问,实现对临界资源访问的安全性

  • 互斥的实现技术:互斥锁/信号量
  • 实现互斥的原理:只要保证同一时间只有一个执行流能够访问资源就是互斥
    对临界资源进行状态标记:没人访问的时候标记为1, 表示可访问;有人正在访问的时候, 就标记为0,表示不可访问;在对临界资源进行访问之前先进行状态的判断,决定是否能够访问,不能访问则使其休眠

二、互斥锁

1、概念:其实就是一个计数器,只有0/1的计数器,用于标记资源当前的访问状态 1-可访问 0-不可访问
2、实现:互斥锁想要实现互斥,每个线程在访问临界资源之前都要先访问同一个互斥锁(加锁) ; 意味着互斥锁本身就是一个临界资源,(涉及 到计数器的修改修改过程必须保证安全,因为如果连自己都保护不好,就不能 保护别人)
3、互斥锁的计数器操作如何实现原子性:

1.将cpu寄存器上的值修改为0,然后与内存中计数器进行数据交换(意味着这时候计数器变程了0,谁来访问,都是-种不可访 问状态,别人都进不去,这时候,寄存器就可以慢慢判断是都可以访问了)
2.若寄存器交换后数据为0,则表示当前不可访问,则将pcb状态置为阻塞状态,线程将被挂起等待,若寄存器交换后数据 为1,则表示当前可以访问,则加锁操作直接返回,表示加锁成功–继续可以访问资源
3.访问完数据之后,要进行解锁操作(将内存中计数器的值再修改回来)

1.互斥锁是一个计数器, 本身的计数操作是原子性(如何保证自己的原子性)
2.互斥锁如何实现互斥,通过在访问临界资源之前先加锁访问互斥锁,来进行状态判断是否可加锁

4、互斥锁的代码操作流程:

1.定义互斥锁变量
pthread_ mutex t mutex;
2.初始化互斥锁
mutex=PTHREAD
MUTEX INITIALIZER
int pthread_ mutex_ init(pthread_ mutex. t *mutex,pthread_ mutexattr_ t *attr)
mutex:互斥锁变量首地址
attr:互斥锁属性—通常置NULL,
3.在对临界资源访问之前,先加锁(访问锁,判断是否可以访问) — 保护对临界资源访问的过程
int pthread_ mutex_ lock(pthread mutex_ t *mutex);阻塞加锁—如果不能加锁,则一直等待
int pthread_ mutex_trylock(pthread_ mutex_ t *mutex);非阻塞加锁—如果不能加锁,则立即报错返回,若可以加锁,则 加锁后返回
4.在对临界资源访问完毕之后,记得解锁(把状态标记为可访问)
int pthread_ mutex_ unlock(pthread_ mutex_ t *mutex);
5.不使用锁了,最终要释放资源,销毁互斥锁
int pthread_ mutex_destroy(pthread_ mutex_ t *mutex);

三、死锁

1、概念:多个执行流对锁资源进行争抢访问,但是因为推进顺序不当,而导致互相等待;最终造成程序流程无法继续的情况

2、死锁产生的必要条件:必须具备的条件,如果不具备就无法造成死锁-- -知道了必要条件,就可以实现预防以及避免

  • 互斥条件:一个锁不能大家同时加,我加了锁,别人就不能再加了----同一时间只有一个线程能够加锁
  • 不可剥夺条件:我加的锁,别人不能解,只有我能解锁 线程加的锁,只有自己能解
  • 请求与保持条件: 吃着碗里的,看着锅里的; 抢到了锁A,然后去抢锁B,但是抢不到锁B,也不释放锁A
  • 环路等待条件:线程1抢到了锁A,然后去抢锁B,但是抢不到锁B ;线程2抢到了锁B,然后去抢锁A;但是抢不到锁A

3、如何预防死锁:防患于未然----在编写代码过程中注意破坏产生的必要条件即可
4、如何避免产生死锁:死锁检测算法/银行家算法

四、条件变量

1、概念:实现同步的思路向用户提供两个接口(一个是让线程陷入阻塞休眠的接口;一个是唤醒线程休眠的接口)+pcb等 待队列
2、同步:通过条件判断(什么时候能够访问资源,什么时候不能访问;若不能访问就要使线程阻塞;若能访问了就要唤醒线 程),实现线程对临界资源访问的合理性
3、条件变量:只是向外提供了等待与唤醒的接口,却没有提供条件判断(条件变量本身并不具备判断什么时候该等待,什么时候 该唤醒)的功能;意味着,条件判断需要用户自己来完成
4、条件变量提供的接口功能:

1.定义条件变量
pthread_cond_t cond
2.初始化条件变量
pthread_ cond_init(pthread_ cond_ t *cond, pthread_ condattr_t *attr);/ cond=PTHREAD_COND_ INITIALIZER
3.一个线程等待的接口:
pthread_ cond_ wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
条件变量是搭配互斥锁使用的:条件变量并不提供条件判断的功能,需要用户去判断(通常条件的判断是一个临界资源的访问) ;因此这个临界资源的访问,就需要受保护,使用互斥锁保护。
pthread_ cond_ timedwait(pthread_ cond_ t *cond, pthread_ mutex_ t *mutex, struct timespec *abstime);
限制等待时长的阻塞操作:等待一段指定的时间,时间到了调用就会报错返回-- ETIMEDOUT
4.一个唤醒线程的接口:
pthread_cond_ signal(pthread_cond_t *cond); //唤醒至少一个等待的线程
pthread_cond_ broadcast(pthread_ cond_ t *cond)//唤醒所有等待的线程
5.若不使用条件了则销毁释放资源:
pthread_ cond_destroy(pthread_ cond _t *cond);

5、操作流程:用户不能访问资源的时候调用接口陷入等待,其它线程产生资源,然后调用接口唤醒等待队列中的线程;是否能够 访问的条件判断需要用户自己完成,并且需要互斥保护

1.加锁
2.用户自己进行条件判断,不能访问,则调用pthread _cond _wait陷入等待
3.被唤醒之后能够访问,则访问数据,获取资源
4.唤醒生产资源的线程
5.解锁

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值