《多线程程序常见Bug剖析(下)》有15个想法

  1. 常见的解决方案中加锁进行同步是有效方法,也想对最费额外性能;
    进行条件检查,可能会引入新的潜在危险,如 Ad Hoc Synchronization造成的。
    个人浅见

    1. 同意。加锁不是万能的,除了容易带来死锁等问题外,性能的损失也是最大的;
      引入条件判断确实会带来新的问题,事实上修复多线程Bug的过程中很多最开始的修复方案都带来了新的bug:)

  2. 请问博主,目前并发算法的proof of correctness是否都是基于Lamport 77年的论文的?

    1. Lamport大神当然是这个方向的先驱 验证并行算法正确性用的最多的是Model Check 例如这篇文章:http://research.microsoft.com/en-us/um/people/lamport/pubs/dcas.pdf

  3. 现在lock很高效了。
    如果特殊地方(这里指的特殊就要看需求了)lock设计的好,lock的性能损失将不是特别大,
    还是可以接受的

    1. 恩 看能不能满足性能需求了。lock想要提高性能就得用细粒度的,但是会带来两个问题:1是锁本身的overhead会增加,2是容易出死锁、活锁、护航之类的bug

  4. 我这有一个例子,涉及volatile的使用以及多核并发的问题。
    TICK模块本身有一个线程,每隔一段时间调用TickRolling更新tick;
    同时提供TickGet接口供其它线程使用。
    它使用两个读缓冲区互相交换来避免使用锁保护共享变量,但存在两个问题;
    有人能看出来吗?

    unsigned int m_uiRollingTickHigh[2];
    unsigned int m_uiRollingTick[2];
    unsigned int m_uiTickIndex;

    int TickGet(unsigned int *puiHigh, unsigned int *puiLow)
    {
    unsigned int uiIndex;

    uiIndex = m_uiTickIndex;
    *puiHigh = m_uiRollingTickHigh[uiIndex];
    *puiLow = m_uiRollingTick[uiIndex];
    /*
    {
    unsigned int uiOther;
    uiOther = m_uiRollingTick[1 – uiIndex];

    m_uiTickDebugRecIdx[m_uiTickDebugRecIndex] = uiIndex;
    m_uiTickDebugRecMine[m_uiTickDebugRecIndex] = *puiLow;
    m_uiTickDebugRecOther[m_uiTickDebugRecIndex] = uiOther;
    m_uiTickDebugRecIndex = (m_uiTickDebugRecIndex + 1) & (TICK_REC_MAX – 1);
    }
    */

    return 0;
    }

    void TickRolling(unsigned int uiMillSec)
    {
    unsigned int uiRollingTickAndLost;
    unsigned int uiLostTicks = uiMillSec/1000;
    m_uiRollingTickHigh[1] = m_uiRollingTickHigh[0];
    m_uiRollingTick[1] = m_uiRollingTick[0];
    m_uiTickIndex = 1;

    uiRollingTickAndLost = m_uiRollingTick[0] + uiLostTicks;
    if(m_uiRollingTick[0] > uiRollingTickAndLost)
    {
    m_uiRollingTickHigh[0]++;
    }
    m_uiRollingTick[0] += uiLostTicks;
    m_uiTickIndex = 0;
    }

    1. 如果TickRolling和TickGet这两个函数都会被多个线程同时调用,则必须保证对m_uiRollingTickHigh[2], m_uiRollingTick[2],m_uiTickIndex这几个共享变量的读写操作是原子的

  5. hi ,您好。非常感谢您的分享,今天看了您的BLOG后受益匪浅,再次谢谢了哈。向您请教一个问题,即“什么样的数据结构及其操作具有多线程安全性”。就目前所知,单入单出的queue在读写模型里具有线程安全(一个线程读,一个线程写)。但是除了您介绍关于多线程的BUG外,我总结不出较好的判定条件,希望得到您的帮助,谢谢了!

    1. Hi,谢谢你的问题。如果你用C++,请直接使用boost或者C++1x中加入的线程安全的数据结构,如果你使用Java,请直接使用线程安全的queue等数据结构。千万不要自己去写,直接用就好了:)

  6. 加锁会带来死锁问题我遇到过。比如有个数据结构包括一个状态机和一个callback指针,在Running阶段会循环调用callback,若不用锁同步会在Reset操作中使得callback被清零,加锁又会导致库死锁。后来的解决方案没有用所,而是reset操作不对callback指针清零,仅仅清除状态机,并且在另一个线程加上状态机的条件判断即可避免(当然还要确保此时callback中的数据仍是有效的)。

电子邮件地址不会被公开。 必填项已用*标注