多线程--线程安全
Posted 李憨憨_
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程--线程安全相关的知识,希望对你有一定的参考价值。
线程安全
概念:描述的是线程中对临界资源的访问操作是安全的实现:同步与互斥
互斥:通过对临界资源同一时间的唯一访问保证访问操作安全
同步:通过条件判断使对临界资源访问或获取更加合理
互斥的实现
互斥的实现:互斥锁互斥锁:本质就是一个只有0/1的计数器,用于标记临界资源的访问状态
0-不可访问;1-可访问
实现互斥原理:在访问临界资源之前加锁(判断是否可访问),不可访问则阻塞。访问资源完毕之后解锁(将资源状态置为可访问)
互斥锁自身计数的操作是一个原子操作
接口介绍:
1.定义互斥锁变量
pthread_mutex_t mutex;
2.初始化互斥锁变量
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
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 #include<stdio.h>
3 #include<unistd.h>
4 #include<stdlib.h>
5 #include<pthread.h>
6 int tickets = 100;
7 void *scalpers(void *arg)
8 {
9 while(1){
10 if(tickets > 0){
11 usleep(1);
12 printf("I got a ticket: %d\\n", tickets);
13 tickets--;
14 }else{
15 pthread_exit(NULL);
16 }
17 }
18 return NULL;
19 }
20 int main()
21 {
22 pthread_t tid[4];
23 int i = 0;
24 int ret;
25 for(i = 0;i < 4;i++){
26 ret = pthread_create(&tid[i], NULL, scalpers, NULL);
27 if(ret != 0){
28 printf("thread create error\\n");
29 return -1;
30 }
31 }
32 for(i = 0;i < 4;i++){
33 pthread_join(tid[i], NULL);
34 }
35 return 0;
36 }
所以要使用互斥锁
此时就正常了
死锁
死锁:程序运行流程因为某种原因卡死无法继续推进死锁产生的原因:死锁产生的四个必要条件
1.互斥条件:一个资源同一时间只有一个进程/线程能够访问
2.不可剥夺条件:我加的锁只有我能解,别人不能解
3.请求与保持条件:加了A锁后请求B锁,B请求不到,A不释放
4.环路等待条件:线程1加了A锁,请求B锁;线程2加了B请求A
预防死锁:破坏死锁产生的必要条件(3,4)
1.一定保证加/解锁顺序一致;
2.请求不到第二个锁则释放已有的;
避免死锁:银行家算法....... 已有资源 线程已有资源 线程请求的新资源
同步的实现
同步的实现:通过条件判断实现对资源获取的合理性--条件变量条件变量:pcb等待队列+能够使线程阻塞以及唤醒线程阻塞的接口
当线程对临界资源访问不合理的时候,则调用阻塞接口阻塞进程;
若其他线程促使当前线程对资源获取合理,则调用唤醒接口;
条件变量实现同步这里,有等待队列,但是只提供了阻塞以及唤醒线程的接口,至于什么时候阻塞,什么时候唤醒线程需要程序员自己判断
条件变量使用中,对条件判断由程序员自己完成,而条件判断的依据是一个临界资源,访问时需要被保护,因此条件变量需要搭配互斥锁一起使用
接口介绍:
1.定义条件变量
pthread_cond_t cond;
2.初始化条件变量
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int pthread_cond_init(pthread_cond_t* cond, pthread_condattr_t* attr);
3.使线程阻塞
int pthread_cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex);
int pthread_cond_timedwait(pthread_cond_t* cond, pthread_mutex_t * mutex, struct timespec *abstime);
4.唤醒阻塞的线程
int pthread_cond_signal(pthread_cond_t *cond);-至少一个
int pthread_cond_broadcast(pthread_cond_t *cond);-唤醒所有
5.销毁条件变量
int pthread_cond_destroy(pthread_cond_t *cond);
以上是关于多线程--线程安全的主要内容,如果未能解决你的问题,请参考以下文章