0

当我尝试不同的互斥体变体时,最后我找到了 2 个最快的原语。

一种是基于InterlockedExchange(众所周知的方法)

Access:
  while InterlockedExchange(AccessFlag, 1) <> 0 do
Release:
  InterlockedExchange(AccessFlag, 0)

另一种是基于事件的。

Init:
  Event = CreateEvent(Null, false, true, Null);
Access:
  WaitForSingleObject(Event, INFINITE)
Release:
  SetEvent(Event)

基于 InterlockedExchanged 的​​速度总是最快的,但是在失败的情况下它会受到不睡眠的影响。另一方面,它在单个物理处理器(内核)或多个内核上都非常有效。虽然单核测试的小好处是如果我在循环中添加 Sleep(0) 就不会失败。

基于事件的在睡眠时等待非常有用,但是当我测量性能时,我注意到使用这种类型互斥锁的多个线程如果驻留在单个物理处理器上(使用相同值调用的 SetThreadAffinityMask 或在单个物理处理器上进行测试)执行得更快——核心计算机)比在不同的处理器上。根据处理器的类型,这从 x4 (iCore 5) 到 x8 (Xeon) 不等。

至强的一些统计数据

3 个线程,每个线程增加 10 个变量(10,000,000 步),每次增加时使用互斥锁访问它。

  • 多处理器,基于 InterlockedExcchange

    344 毫秒/每毫秒:87,209 / while 循环中的失败:2,487,376(占 3 个线程的总步数的 8%,存在 Sleep(0),但对于多处理器线程可能无用)

  • 多处理器,基于事件

    6187 毫秒/每毫秒:4,848

  • 单处理器,基于 InterlockedExcchange

    281 毫秒/每毫秒:106,761/while 循环中的失败:0(循环内的睡眠(0));

  • 单处理器,基于事件

    765 毫秒/每毫秒:39,215

我假设真正的内核间同步有一些惩罚。但我想将 InterlockedExchange 方法的完美性能与基于事件的方法的正确性(“不工作就睡觉”)“结合”起来。这可能吗?

4

1 回答 1

1

我相信这样做的一种常见方法是仅在有限次数的尝试中旋转 CAS 步骤。如果您的情况没有及时变为现实,那么您将经历“更昂贵”的基于事件的解决方案的开销。

于 2012-12-24T08:35:50.593 回答