多线程与加锁的一些理解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/winter_wu_1998/article/details/83721579
  • 竞争发生在当多线程同时访问同一个内存,各个线程执行的顺序有交叉时。
  • 一般来说,局部变量和参数由于对每个线程是独立的,不会发生竞争。竞争通常发生在全局变量,堆变量等上。
  • 解决竞争最简单的方法就是进入临界区(开始读写公共内存)时屏蔽掉中断,但是这种方法对于多CPU无效,因为该内存可能会被别的CPU中的程序访问。现在更好的方法是屏蔽那片内存的访问(以前是通过锁住总线解决的)。但是还是会有问题,因为这样也屏蔽了时钟中断,可能会陷入死锁。
  • 第二种想法就是加锁,但是简单的在程序级别进行加锁是没用的,因为加锁需要先测试相等,然后增加或减少锁变量两个步骤,这之间可能也会存在竞争。因此现在是在硬件层面实现了原子操作TSL(测试并加锁),这个操作在完成前无法被中断,本质上和下面的自旋锁一样。
  • 加锁的方法有很多,一种叫Peterson的算法可以看我上一篇博客。现在介绍最简单的自旋锁。
while(true != 0)
;
critical_region();
turn = 1;
nonciritical_region();

可以看出自旋锁就是在测试变量不处理的时候进行忙等待。这种方法是假设忙等待的时间很短,一般在内核中使用。和别的方法比优点在于不用切换进程。

  • 最常用的手段就是使用信号量或者更简单一点的互斥量,这里比较简单,不在赘述。
  • 和互斥量经常一起使用的是条件变量,即如果不满足条件就睡眠(释放CPU给其他线程)直到满足条件。他要和互斥量一起使用(互斥量通常作为参数)的原因在于互斥量要保护wait过程不被中断,具体见下面的图片。
    在这里插入图片描述另外,条件变量不想信号量会保存在内存中,如果传递时没有线程在等待条件变量的操作(如唤醒),那么这个信号就会丢失。
    在这里插入图片描述

在这里插入图片描述

  • 由于信号量的操作容易出错,在更高级的语言里(如JAVA),产生个管程的概念,和前面的本质是一样的,只是这里加锁和解锁由编译器实现,减少了出错的可能性。

猜你喜欢

转载自blog.csdn.net/winter_wu_1998/article/details/83721579