多线程(3)--线程安全

线程安全

概念:描述的是线程中对临界资源的访问操作是安全的
  实现:同步与互斥
    互斥:通过对临界资源同一时间的唯一访问保证访问操作安全
   同步:通过条件判断使对临界资源访问或获取更加合理

互斥的实现

互斥的实现:互斥锁
互斥锁:本质就是一个只有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: %dn", 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 errorn");  29             return -1;  30         }  31     }  32     for(i = 0;i < 4;i++){  33         pthread_join(tid[i], NULL);  34     }  35     return 0;  36 }  

多线程(3)--线程安全


所以要使用互斥锁
多线程(3)--线程安全
此时就正常了
多线程(3)--线程安全

死锁

死锁:程序运行流程因为某种原因卡死无法继续推进
  死锁产生的原因:死锁产生的四个必要条件
  1.互斥条件:一个资源同一时间只有一个进程/线程能够访问
   2.不可剥夺条件:我加的锁只有我能解,别人不能解
   3.请求与保持条件:加了A锁后请求B锁,B请求不到,A不释放
   4.环路等待条件:线程1加了A锁,请求B锁;线程2加了B请求A
 预防死锁:破坏死锁产生的必要条件(3,4)
   1.一定保证加/解锁顺序一致;
   2.请求不到第二个锁则释放已有的;
避免死锁:银行家算法....... 已有资源 线程已有资源 线程请求的新资源

同步的实现

同步的实现:通过条件判断实现对资源获取的合理性--条件变量
 条件变量:pcb等待队列+能够使线程阻塞以及唤醒线程阻塞的接口
  当线程对临界资源访问不合理的时候,则调用阻塞接口阻塞进程;
   若其他线程促使当前线程对资源获取合理,则调用唤醒接口;

多线程(3)--线程安全

  条件变量实现同步这里,有等待队列,但是只提供了阻塞以及唤醒线程的接口,至于什么时候阻塞,什么时候唤醒线程需要程序员自己判断

  条件变量使用中,对条件判断由程序员自己完成,而条件判断的依据是一个临界资源,访问时需要被保护,因此条件变量需要搭配互斥锁一起使用

  接口介绍:
    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);

版权声明:玥玥 发表于 2021-05-26 5:14:08。
转载请注明:多线程(3)--线程安全 | 女黑客导航