zoukankan      html  css  js  c++  java
  • 读写锁的一个奇怪表现

    上周做性能调优的时候,发现一个测并发读写的场景数据很奇怪。

    场景是测一个写线程加不同数量的读线程时的读写QPS,结果发现数据大致是下面的样子:

    写线程数    读线程数    写QPS    读QPS
    1          1          4000     40
    1          5          3000     10000
    1          10         3000     20000
    ...
    

    代码大致是这样子的:

    // 写线程
        ReadWriteLockGuard lock(mLock, 'w');
        // do something...
    
    // 读线程
        ReadWriteLockGuard lock(mLock, 'r');
        // do something...
    

    从这段代码看来,当读写线程是1:1时,应该是两个线程轮流抢锁才对,但QPS却显示出写线程抢到锁的次数是读线程的100倍!

    于是我在读写线程的代码中都加一行打印,来看读写线程抢锁的情况:

    // 写线程
        ReadWriteLockGuard lock(mLock, 'w');
        // do something...
        cout << "w" << endl;
    
    // 读线程
        ReadWriteLockGuard lock(mLock, 'r');
        // do something...
        cout << "r" << endl;
    

    结果很出乎我的意料:

    r
    w
    w
    w
    ...
    w
    r
    w
    w
    ...
    

    总之写线程连续抢到若干次锁后,可怜的读线程才抢到一次锁。

    很奇怪的现象。

    我之前对读写锁抢锁流程的理解:

    1. 如果当前没有线程持有锁,那么第一个去抢锁的活动线程会拿到锁;
    2. 如果当前持有者释放锁,那么所有排队的线程会进行抢锁;
    3. 排队的线程中有等写锁的线程时,申请读锁会阻塞(写锁优先)。

    现在看来这个理解是有问题的,无法解释这一现象。

    和同事交流了一下,读写锁抢锁流程可能是这样的:

    1. 如果有线程申请锁阻塞,会首先调用SpinLock一会,之后如果还是没抢到锁,那么内核将其设置为睡眠状态,并加入等待队列;
    2. 当前持有线程释放锁后,内核将所有等待队列中的睡眠线程唤醒,加入调度队列;
    3. 进入调度队列的竞争线程在被调度运行后,开始抢锁。

    从这个流程来看,我遇到的这种情况可以这么解释:

    1. 读线程首先运行,抢到锁;
    2. 因为是写优先,在读线程结束后锁肯定会让给写线程;
    3. 写线程释放锁后,读线程被唤醒,此时还处于等待状态,未运行,不能抢锁;
    4. 写线程没有睡眠,重新抢锁,此时没有写优先的影响,成功抢到锁;
    5. 读线程开始运行,抢锁失败,重新睡眠。

    在读线程增多以后,写线程释放锁后就不一定能抢到锁了,因此会有一定的时间在睡眠,这样进一步增大了读线程抢到锁的概率,因此就观察到读的QPS猛涨的情况。

    上面的猜测还未得到验证,有空还是得看看pthread_read_write_lock的实现啊。

  • 相关阅读:
    转载:CODE CSDN Git 配制方法介绍
    版本管理之Git(二):Win7上Git安装及简单配置过程
    Html_color code表示
    Android 自动化测试—robotium(十一) robotium实现微博绑定
    转载:Android自动化测试- 自动获取短信验证码
    Android 自动化测试—robotium(九) Junit_report测试报告重定向输出到终端SDCard
    每日一问:面试结束时面试官问"你有什么问题需要问我呢",该如何回答?
    常见的几个Python面试题
    使用python解析Json字符串-获取Json字符串关键字
    Android测试之 APK重签名方法
  • 原文地址:https://www.cnblogs.com/fuzhe1989/p/3876492.html
Copyright © 2011-2022 走看看