前言:
目前各位老铁们对“线程安全和非线程安全的区别”大致比较关切,看官们都想要知道一些“线程安全和非线程安全的区别”的相关知识。那么小编同时在网络上汇集了一些对于“线程安全和非线程安全的区别””的相关知识,希望大家能喜欢,兄弟们一起来了解一下吧!文章目录前言线程安全互斥的实现:互斥锁死锁同步的实现----条件变量前言
上一个博客总结了线程控制:创建/终止/等待/分离。需要了解请点击:链接: 线程控制.
线程安全
线程安全:多个执行流对临界资源的争抢访问,但是不会出现数据二义性;
线程安全的实现:
同步:通过条件判断保证对临界资源访问的合理性
互斥:通过同一时间对临界资源访问的唯一性实现临界资源访问的安全性
互斥的实现:互斥锁
互斥锁实现的原理:互斥锁本身是一个只有0/1的计数器,描述了一个临界资源当前的访问状态,所有执行流在访问临界资源,都需要先判断当前的临界资源状态是否允许访问,如果不允许则让执行流等待,否则可以让执行流访问临界资源,但是在访问期间需要将状态修改为不可访问状态,这期间如果有其他执行流想要访问,则不被允许。
互斥锁具体的操作流程以及接口介绍:
定义互斥锁变量 pthread_mutex_t mutex;pthread_mutex_init(pthread_mutex_t mutex,pthread_mutexattr_t attr);pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;定义并且初始化在访问临界资源之前进行加锁操作(不能加锁则等待,可以加锁则修改资源状态,然后调用返回,访问临界资源)
pthread_mutex_lock(pthread_mutex_t mutex);
pthread_mutex_trylock(pthread_mutex_t *mutex);(非阻塞:不能加锁立即报错返回)
挂起等待:将线程状态置为可中断休眠状态–表示当前休眠;
被唤醒:将线程状态置为运行状态在临界资源访问完毕之后进行解锁操作(将资源状态置为可访问,将其他执行流唤醒)
pthread_mutex_unlock(pthread_mutex_t mutex);销毁互斥锁
pthread_mutex_destroy(pthread_mutex_t mutex)
所有的执行流都需要通过同一个互斥锁实现互斥,意味着互斥锁本身就是一个临界资源,大家都会访问
如果互斥锁本身的操作都不安全如何保证别人安全,所以互斥锁本身的操作首先必须是安全的------互斥锁自身计数的操作是原子操作
我们可以发现互斥锁,我们实现代码中有四个线程,但是模拟抢票的时候,只有一个线程在抢,所以互斥并不保证合理。
死锁
多个执行流对锁资源进行争抢访问,但是因为访问推进顺序不当,造成互相等到最终导致程序流程无法继续推进,这时候就造成了死锁。
死锁实际是一种程序流程无法继续推进,卡在某个位置的一种概念。
死锁产生的必要条件:
1.互斥条件
2.不可剥夺条件:我加的锁,别人不能解,只有我能解锁
3.请求与保持条件:我加了A锁,然后去请求B锁;如果不能对B加锁,则也不释放A锁
4.环路等待条件:我加了A锁,然后去请求B锁,另一个人加了B锁,然后去请求A锁。
死锁的预防:破坏死锁产生的必要条件(主要避免3和4两个条件的产生)
死锁的避免:银行家算法
互斥并不保证合理/同步并不保证安全
同步的实现----条件变量
同步的实现:通过条件判断实现临界资源访问的合理性– 条件变量
条件变量:向外提供了一个使线程等待的接口和唤醒线程的接口+pcb的等待队列
当前是否满足获取资源的条件,若不满足,则让执行流等待,等到满足条件能够获取的时候再唤醒执行流
实现同步:两个功能接口:让执行流等待的接口和唤醒执行流的接口
使用接口介绍:
定义条件变量----pthread_cond_t cond;初始化条件变量
pthread_cond_init(pthread_cond_t cond,pthread_condattr_t attr)
pthread_cond_t cond=PTHREAD_COND_INITIALIZER;若资源获取条件不满足时调用接口进行阻塞等待:条件变量是搭配互斥锁一起使用的
pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);-----一直死等别人的唤醒
pthread_cond_timedwait(pthread_cond_t *,pthread_mutex_t *,struct timespec *)----设置阻塞超时时间的等待接口唤醒线程的接口:
pthread_cond_signal(pthread_cond_t *)----唤醒至少一个等待的线程
pthread_cond_broadcast(pthread_cond_t *)----唤醒所有等待的线程销毁条件变量:
pthread_cond_destroy(pthread_cond_t );
示例:
注意事项:
条件变量使用中对条件的判断应该使用while循环多种角色线程应该使用多个条件变量
第一种情况:多个顾客线程,因为没有饭等待,这时候一个厨师做了一碗饭,去唤醒顾客(至少唤醒一个),但是顾客只能有一个加锁,其他两个顾客线程卡在加锁这里,吃完饭后解锁,但是这时候加上锁的不一定是厨师线程,有可能是等待的两个顾客线程,那这个顾客线程就在没有饭的情况下吃了一碗饭----逻辑错误。那么避免这种逻辑错误,条件的判断应该是一个循环判断,顾客线程被唤醒加锁成功后重新判断有没有饭,没有休眠,有就等待
第二种情况:一个顾客线程吃完饭,一条队列上有3个厨师线程,顾客线程进入队列,厨师做好饭,唤醒的可能就不是顾客线程,被唤醒的厨师线程发现有饭,重新休眠,导致程序阻塞。解决方案----不同角色的线程应该挂在不同的等待队列上等待,唤醒的时候,就有目的性的唤醒,因此多个角色需要使用多个条件变量。
标签: #线程安全和非线程安全的区别