当前位置:嗨网首页>书籍在线阅读

05-互斥量的性能

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

30.1.3 互斥量的性能

使用互斥量的开销有多大?前面已经展示了递增共享变量程序的两个不同版本:没有使用互斥量的程序清单 30-1 和使用互斥量的程序清单30-2。在x86-32架构的Linux 2.6.31(含NPTL)系统下运行这两个程序,如令单一线程循环1000万次,前者共花费了0.35秒(并产生错误结果),而后者则需要3.1秒。

乍看起来,代价极高。不过,考虑一下前者(程序清单30-1)执行的主循环。在该版本中,函数threadFunc()于for循环中,先递增循环控制变量,再将其与另一变量进行比较,随后执行两个复制操作和一个递增操作,最后返回循环起始处开始下一次循环。而后者——使用互斥量的版本(程序清单30-2)执行了相同步骤,不过在每次循环的前后多了加锁和解锁互斥量的工作。换言之,对互斥量加锁和解锁的开销略低于第1个程序的10次循环操作。成本相对比较低廉。此外,在通常情况下,线程会花费更多时间去做其他工作,对互斥量的加锁和解锁操作相对要少得多,因此使用互斥量对于大部分应用程序的性能并无显著影响。

进而言之,在相同系统上运行一些简单的测试程序,结果显示,如将使用函数 fcntl()(见55.3 节)加锁、解锁一片文件区域的代码循环2000万次,需耗时44秒,而将对系统V信号量(semaphore)(见47章)的递增和递减代码循环2000万次,则需要28秒。文件锁和信号量的问题在于,其锁定和解锁总是需要发起系统调用(system call),而每个系统调用的开销虽小,但颇为可观(见3.1节)。与之相反,互斥量的实现采用了机器语言级的原子操作(在内存中执行,对所有线程可见),只有发生锁的争用时才会执行系统调用。

Linux上,互斥量的实现采用了futex(源自“快速用户空间互斥量”[fast user space mutex]的首字母缩写),而对锁争用的处理则使用了futex()系统调用。本书无意描述futex,其设计意图也并非供用户空间(user space)应用程序直接使用,不过[Drepper, 2004(a)]给出了详细描述,还讨论了如何使用futexes来实现互斥量。[Franke et al., 2002]是一篇由futex开发人员所撰写的论文(已经过时),介绍了futex的早期实现以及因其所带来的性能提升。