设为首页 加入收藏

TOP

10.2 对(代码)块的同步访问:临界区
2013-10-07 15:05:46 来源: 作者: 【 】 浏览:82
Tags:10.2 代码 同步 访问 临界

10.2  对(代码)块的同步访问:临界区

对于大多数同步需求来说,单个原子操作是不够的,它们往往需要对所谓的临界区的独占访问[Bulk1999]。例如,如果你有两个变量需要原子地进行更新,你就必须使用一个同步对象来确保每个线程对该临界区的访问都是独占地进行的,像这样:

  1. // 共享对象  
  2. SYNC_TYPE   sync_obj;  
  3. SomeClass   shared_instance;  
  4. . . .  
  5. // 被多线程调用的代码段  
  6. lock(sync_obj);  
  7. int i = shared_instance.Method1(. . .);  
  8. shared_instance.Method2(i + 1, . . .);  
  9. unlock(sync_obj);  

Method1()和Method2()这两个操作必须以一种不被中断的顺序进行。因此,调用它们的代码被包裹在获取和释放同步对象之间。通常,任何对此类同步对象的使用的代价都是高昂的,因而需要某些途径来使这些开销最小化甚至完全避免。

将同步对象用于保护临界区的做法之所以代价高昂,原因有二:第一,同步对象的使用本身可能代价高昂。例如,考虑表10.1中的时间(以毫秒为单位),它们是基于对4个Win32同步对象的1000万次"获取-释放"周期,以及由两个空函数调用所代表的控制场景。结果一目了然地显示出来,使用同步对象的代价是相当可观的,可能高达常规函数调用开销的150倍!

表10.1

< xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

对称多处理器

无(控制)

117

172

CRITICAL_SECTION

1740

831

atomic_integer

1722

914

互斥体

17891

22187

信号量

18235

22271

事件

17847

22130

将同步对象用于保护临界区的第二个开销是由那些被拒绝在临界区之外的线程所导致的。临界区越长,就越是可能带来这种代价,因而最好尽量保持临界区的短小,或者将它们分解为多个"子临界区",就像在6.2节讨论的那样。然而,由于获取和/或释放同步对象的函数调用的代价可能会非常高,所以在临界区分解和导致"被拒"线程的长时间等待之间必须求得一个微妙的平衡。只有根据实际情况对性能进行评测你才能得到一个确定性的答案。

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇19.1 隐式转换 下一篇10.1 对整型值的同步访问

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: