线程同步与互斥 以及死锁问题

当多个线程同时访问共享数据时,可能会由于线程间不断切换导致操作系统的多次调用,从而引起访问冲突。想要解决这个问题,我们可以为这份共享数据加入互斥锁。

互斥锁的内部实现:

lock:

    movb $0 %al

    xchgb %al mutex  //交换寄存器al和mutex中的内容  是原子的

    if(al>0)

       retuen 0

    else

      goto lock //挂起等待

unlock:

    movb $1 mutex  //唤醒等待mutex的线程

    return 0; 

下面以两个进程同时对全局静态变量count进行++操作为例:

  1 #include<stdio.h>
  2 #include<pthread.h>
  3 
  4 static int count = 0;
  5 static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;//定义锁
  6 void *pthread(void* arg)
  7 {
  8     int tmp = 0;
  9     int i = 5000;
 10     while(i--)
 11     {
 12         pthread_mutex_lock(&lock); //加锁
 13         tmp = count;
 14         printf("this is %d thread,count is %d\n",(int)arg,tmp);
 15         count = tmp +1;
 16         pthread_mutex_unlock(&lock); //解锁
 17     }
 18     return (void*)2;
 19 }
 20 int main()
 21 {
 22     pthread_t tid1,tid2;
 23     pthread_create(&tid1,NULL,pthread,(void*)1);
 24     pthread_create(&tid2,NULL,pthread,(void*)2);
 25 
 26     void* status = NULL;
 27     pthread_join(tid1,&status);
 28     pthread_join(tid2,&status);
 29     printf("count is %d\n",count);
 30     return 0;
 31 }
 //未加互斥锁
this is 1 thread,count is 5304
this is 1 thread,count is 5305
this is 1 thread,count is 5306
this is 1 thread,count is 5307
this is 1 thread,count is 5308
this is 1 thread,count is 5309
this is 1 thread,count is 5310
this is 1 thread,count is 5311
count is 5312
 
 //加入互斥锁
this is 1 thread,count is 9993
this is 1 thread,count is 9994
this is 1 thread,count is 9995
this is 1 thread,count is 9996
this is 1 thread,count is 9997
this is 1 thread,count is 9998
this is 1 thread,count is 9999
count is 10000

从上面程序的执行结果看:不加互斥锁时,由于count++分两步来执行,增加了系统的调用和线程的切换,导致结果不正确。而加入互斥锁之后,解决了线程访问冲突问题。


虽然加入互斥锁解决了线程访问冲突的问题,但也有可能会引起死锁。

死锁:

是指多个线程在运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,它们都将无法向前推进。


产生死锁的原因

  1. 竞争资源(主要指非剥夺性资源和临时资源):

    1)竞争非剥夺性资源:非剥夺性资源是指当系统把资源分配给某个线程后,不嫩强行手绘资源,只有当它用完后自行释放的资源。 例如现在有P1、P2两个进程,两个进程都需要A、B两个资源同时存在才能继续向前推进,而此时P1进程拥有A资源,P2进程拥有B资源。两个进程都在等待对方释放资源,此时就会陷入僵局,也就形成了死锁。

    2)竞争临时资源:临时资源是指由某一线程产生,再被其他线程用一段时间后便无用的资源。此时造成死锁的原因是多个线程产生资源和申请资源的顺序不当造成的。如有P1、P2、P3三个线程,线程P1、P2、P3分别产生S1、S2、S3资源。此时的运行顺序如果是

    P1: ... Request(s3);Release(s1)...

    P2: ... Request(s3);Release(s1)...

    P3: ... Request(s3);Release(s1)... 则会造成死锁。

  2. 进程间推进顺序非法:线程在运行过程中,请求和释放资源的顺序不当造成的死锁。



产生死锁的四个必要条件

  1. 互斥条件:在一段时间内某资源只能被一个线程占用。其他请求该资源的线程只能等待。

  2. 请求和保持资源:线程已保持了至少一个资源,又提出新的资源请求,而该资源又被其他线程占用

  3. 不剥夺条件:已占有的资源为非剥夺性资源。

  4. 环路等待条件:在发生死锁时,必须存在一个进程---资源的环形链。


死锁的预防

使产生死锁的四个必要条件中的2 3 4 条件中的一个不能成立。

  1. 摒弃“请求和保持”条件:要求线程在申请资源时必须把所要求的资源全部申请完。

  2. 摒弃“不剥夺”条件:当一个线程已经拥有了一些资源时,又有新的资源请求,如果要申请的资源已被占用,必须释放已经拥有的所以资源。

  3. 摒弃“环路等待”条件:为系统中所有资源编上编号,每个进程申请资源时都必须按照编号的顺序来申请。



死锁的避免

只要使系统始终都处于安全状态,便可避免死锁的产生。

安全状态:系统能按某种线程顺序(安全序列)来为每个线程分配其所需资源,直至满足每个线程对资源的最大需求,使每个线程都可顺利完成。

最典型的方法是:银行家算法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章