并行编程锁优化,这里记录它的原理和实践。
优化方法分析
使用自旋锁
普通的锁,比如pthread的mutex基于OS提供的休眠和唤醒机制,如果锁的临界区很短,会造成CPU资源的浪费,并且延迟也比较高。这种情况我们可以考虑使用自旋锁——等待自旋锁的线程不会放弃CPU进入休眠,而是不断的检查锁占用标志,一旦持有锁的线程设置标志释放锁,等待线程可以立即进入临界区。
在测试环境上对pthread线程库的mutex和spinlock的做性能对比。
随着临界区越来越短,自旋锁的相对MUTEX的性能优势越来越明显,当临界区缩短到8us以后,自旋锁可以达到2倍以上的提升。
如果临界区持续时间很长,spinlock并不会比mutex性能差,但CPU占用率会很高,一直是400%(4个核,4*100%);而mutex逐渐接近于100%。主要是因为spinlock等锁时不放弃CPU,空转。所以spinlock应该在临界区比较短的情况下使用,否则很浪费CPU。
然而由于应用程序处于用户态,它的执行可被任意抢占,临界区的执行时间不能准确预期,有可能被耽搁“很久”。所以应用程序中使用自旋锁的实践并不多。
Facebook于今年六月份放出了他们针对多核环境的C++高性能库- folly,里面对自旋锁实现做了改进,更适用于用户态程序。这种改进非常简单,就是先自旋后休眠:
这个简单的改进