• 线程同步有关锁的术语介绍


    在多线程中,锁是一种最常用的同步工具,下面详细讲讲带有锁字的一些术语:

    1.锁的具体实现原理:

    (1).互斥锁(Mutex)

    用一个“互斥锁”的对象,任一时刻,只有一个线程能访问这个对象,也就是把代码分成一个个临界区域。在Linux下伪代码如下:

    pthread_mutex_t mutex;
    
    pthread_mutex_init (&mutex, NULL); /*初始化锁*/
    
    pthread_mutex_lock(&mutex); /*获取互斥锁,也就是加锁*/
    
    ... /*临界区*/
    
    pthread_mutex_unlock(&mutex); /*解锁互斥锁*/

    如图,中间的临界区就实现了加锁,每次只有一个线程才能访问。基本上我们线程同步用的都是互斥锁。

    2.自旋锁(Spin Lock)

    跟互斥锁类型,都是为了实现互斥访问某个对象,但是互斥锁在资源被占用的时候会进入睡眠,而自旋锁则会一直循环去探测能否获取资源,在某种意义上,就是一直while循环探测。所以自旋锁很容易就占用cpu过多,但是不需要线程的休眠调度等,会效率比较高,适用加锁时间很短的情况。

    3.读写锁(RWLock)

    读写锁就是一个特殊的自旋锁,只是把需要进入临界区的访问者分成读者和写者,写者是排他的,但是允许多个读者同时存在。也就是说如果没有读者和写者,那么写者可以立刻获得读写锁,否则它必须自旋在那里,直到没有任何写者或读者。如果读写锁没有写者,即使有其他读者,这个读者也可以立即获得该读写锁,否则读者必须自旋在那里,直到写者释放该读写锁。

    互斥锁跟自旋锁一些优缺点:

    Spinlock优点:没有昂贵的系统调用,一直处于用户态,执行速度快。

    Spinlock缺点:一直占用cpu,而且在执行过程中还会锁bus总线,锁总线时其他处理器不能使用总线。

    Mutex优点:不会忙等,得不到锁会sleep。

    Mutex缺点:sleep时会陷入到内核态,需要昂贵的系统调用。

    2.锁的一些分类

    1.递归锁(Recursive Lock)和非递归锁(Non-Recursive Lock)

    两个唯一的区别就是一个线程可以多次获取一个递归锁,而不会导致死锁,而多次获取一个非递归锁就会导致死锁。如下:

    mutex_init(&mutex);
    void fun()
    {
      lock(&mutex);
      //do something1
      fun2();
      unlock&mutex);
    }
    
    void fun2()
    {
      lock(&mutex);
      //do something2
      unlock(&mutex);
    }

    在fun()函数加锁调用了fun2(),而fun2()也加了锁,如果是非递归锁,那么fun获取了mutex,fun2再去获取mutex,就会导致死锁了。

    2.乐观锁(Optimistic Lock)和悲观锁(Pessimistic Lock)

    主要是用于关系型数据库存储。乐观锁,大多是基于数据版本(Version)记录机制实现,即为数据增加一个版本标识。读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。以后提。优点是对于并发的数据库读取,避免了长时间的加锁开销等待,缺点也比较明显,可能导致不正确的数据存入数据库。悲观锁就比较容易理解了,也就是在整个数据库操作中,数据都处于锁定状态。也就是说在数据进行一个读的事务中,所有对整个数据的修改都没法进行。

    3.死锁(Dead Lock)和活锁(Live Lock)

    死锁大家应该都比较清楚,简单地说,就是进入死等待,例如P1占用了资源A,请求资源B,而P2占用了资源B,请求资源A,这样就导致双方一直在等待。而活锁就是资源一直轮不到自己使用,导致一直饥饿,例如如果事务T1封锁了数据R,事务T2请求封锁R,于是T2等待。T3也请求封锁R,当T1释放了R上的封锁之后系统首先批准了T3的请求,T2仍然等待。然后T4又请求封锁R,当T3释放了R上的封锁之后系统又批准了T4的请求,...,T2有可能永远等待,这就是活锁的情形。

    主要是一些概念的介绍,具体的还需要具体去用了才能体会。

    谢谢指教。

  • 相关阅读:
    golang-switch结构辨析有话
    不用中间变量交换变量值-golang版
    vue element ui表单验证不通过,滚动到页面上第一个验证失败的输入框位置
    表单校验中使用v-if和v-else来判断是福哦要校验时的注意项
    如何修改本地项目关联的远程仓库地址
    vue-cli3如何访问public文件夹下的静态资源
    Git 命令行的各种退出方式
    elementui表格如何在表头每个列标题后面插入图片用于插入tooltip
    js 把一个二叉树类型的对象转化为普通对象
    element-ui树结构设置默认选中节点时改变传入的数组树结构没有变化
  • 原文地址:https://www.cnblogs.com/vicstudio/p/3379830.html
Copyright © 2020-2023  润新知