标签:操作 无法 卡死 生产 进入 临界资源 就是 解锁 银行
线程安全
可重入/不可重入:针对函数,多个执行流中是否可以同时进入函数运行而不出现问题
概念:指多个线程同时处理操作临界资源而不会出现数据二义性,则称是线程安全的
二义性:在线程中是否对临界资源进行了非原子操作
如何实现线程安全:
同步(保证合理):临界资源的合理访问(时序可控)
互斥(保证安全):临界资源同一时间唯一访问
如何实现互斥:(首先自身是安全的)
互斥锁:(黄牛抢票程序)
使用一个0/1的原子操作的计数器(图片):
1 -> 表示可以加锁,加锁就是计数-1 .
操作完毕后要解锁,解锁就是计数+1
0 -> 表示不可以加锁,不能加锁则等待
操作步骤:
1.定义互斥锁变量
pthread_mutex_t mutex;
2.初始化互斥锁变量
int pthread_mutex_init()
3.加锁/解锁--->要在临界资源访问之前进行
阻塞加锁,加不上锁就阻塞:
int pthread_mutex_lock()
非阻塞加锁,加不上则直接报错返回:
int pthread_mutex_trylock()
限时阻塞加锁:
int pthread_mutex_timedlock()
*加锁之后要在线程任意有可能退出的地方解锁
解锁:
int pthread_mutex_unlock()
4.销毁互斥锁
int pthread_mutex_destroy()
死锁:(在多个锁的使用时,在对加锁的推进顺序使用不当的造成)
因为对一些无法加锁的锁进行加锁,而导致程序卡死
产生场景:
1.加锁/解锁的顺序不同
** 2....
**死锁产生的必要条件:
1.互斥条件(我操作的时候别人的能操作)
2.不可剥夺条件(我的锁,别人不能解)
3.请求与保持条件(拿着手里的,请求其他的,其他的不能请求到,手里的也不放)
4.环路等待条件(3)
如何预防死锁:破坏死锁产生的必要条件
**避免死锁:
1.死锁检测算法
2.银行家算法
如何实现同步:临界资源访问的合理性——生产出来才能使用——等待加唤醒
没有资源则等待(这是一种死等),生产资源后唤醒等待
线程1如果操作条件满足,则操作,否则进行等待
线程2促进条件满足,唤醒等待的线程
条件变量:
1.定义一个条件变量
pthread_cond_t
2.初始化条件变量
int pthread_cond_init()
3.等待/唤醒
死等待:
int pthread_cond_wait()//先解锁在等待,使用原子操作保证安全
——集合了解锁后挂起的操作(原子操作),有可能还又没来得及挂起就已经有人唤醒——则导致白唤醒,
因为含有临界资源,就必须加锁保护
此操作共包含了3个操作:
1.解锁 2.休眠 3.被唤醒后加锁
限时等待,超时后则返回:
int pthread_cond_timedwait()
广播唤醒:(唤醒等待的人所有人)
int pthread_cond_broadcast()
唤醒至少一个等待的人:
int pthread_cond_signal()
4.销毁条件变量
int pthread_cond_destroy()
条件变量为什么要搭配互斥锁使用:
因为条件变量本身只提供等待与唤醒的功能,因此具体什么时候的等待需要
用户来进行判断,这个条件的判断,通常涉及临界资源的操作(其他线程要通过修改文件,来促使条件满足)
而这个临界资源二点操作应该受保护,因此搭配互斥锁使用。
加锁:
条件判断-不满足
1.解锁
2.等待
线程安全
标签:操作 无法 卡死 生产 进入 临界资源 就是 解锁 银行
原文地址:https://www.cnblogs.com/cuckoo-/p/11444436.html