【问题标题】:Concurrency between threads without locks? [closed]没有锁的线程之间的并发? [关闭]
【发布时间】:2013-01-22 10:58:30
【问题描述】:

我被问到如何在不使用锁的情况下实现线程之间的并发,给定无限的内存。我尝试查找它,但找不到不使用任何锁的答案。这应该是可能的......

【问题讨论】:

  • 投票结束不是一个问题,你应该谷歌lock-free programming
  • 我不明白为什么这不是一个问题。问题是“在无限内存的情况下,如何在不使用锁的情况下实现线程之间的并发?”。如,将使用什么方案?读写是如何工作的?
  • 如果是这个问题,你应该把这个问题放在你的问题中。
  • 问题通常不是并发;现代多核 CPU 提供了这一点。问题通常是线程之间的同步,同时它们共享相同的内存,这是一个更难的问题。

标签: c++ c multithreading operating-system thread-safety


【解决方案1】:

大多数现代 CPU 支持一组原子操作,可用于协调对数据的无锁访问(这些 CPU 指令通常用于实现锁定库函数)。例如,Sun Ultrasparcs 有一条比较与交换 (CAS) 指令:要使用它,您首先通常将内存地址读入 CPU 寄存器,然后计算所需的新值,然后使用 CAS - 指定原始值和新值;当且仅当内存内容仍然是原始值时,新值才会写入该内存。因此,这并不能防止竞争条件导致您的更新尝试失败,但它可以让您检测到该失败,然后确定如何处理它。通常,您循环并重试 - 首先在您计算新值并尝试更新时读取其他线程写入该内存的任何值。

这可能有点令人困惑,所以让我们举一个更具体的例子。假设您需要计算所有线程完成的操作数 - 您可以在线程启动之前将计数器设置为 0,然后让每个线程使用 do { read/add-1/CAS } while (failure) 逻辑来增加计数器。

【讨论】:

  • 我的主要困惑:如果您检查该值并且自上次读取以来它已更新,则循环。这个值怎么可能在下一次迭代中没有更新?我是否误解了我们在下一次迭代中所做的事情?我们还在读取相同的值吗?或者可能是它的不同版本?
  • 多核 CPU 实现了cache coherence protocol,它确保对高速缓存行的写入和读取将在核心之间保持一致。通常编译器的工作是把你的语言的内存模型翻译成 CPU 的内存模型,所以你不必太担心。
  • @ZeBlob:经常,但这确实取决于您在哪个系统上工作。例如 - Sun 工作站可能有多个 CPU,并且显式机器代码指令充当内存屏障来协调指定的同步。在 C++03 的情况下,没有提到线程安全,程序员需要了解他们的系统和编译器的行为。
  • @user1136342:是的——你误会了。让我们更明确地看一下递增共享计数器的例子:逻辑基本上是do { int proposed = shared_counter + 1; success = cas(shared_counter, proposed); } while (!success);。如果另一个线程在读取proposed = ... 中的shared_counter 之间更新,那么cas 将失败,您将循环读取更新的shared_counter - 它可能包含来自任意数量的其他线程的任意数量的增量,但是您将获得当前值,然后如果您赢得更新它的比赛,您可以继续。
【解决方案2】:

这是完全可能的,而且非常简单,只要线程:

  • 不共享任何数据 或
  • 共享数据,但只从共享的数据中读取而不写入。

但是,一旦涉及到写入共享数据,事情就会变得复杂。这是你需要start reading up的地方。

【讨论】:

    【解决方案3】:

    您可以查看软件事务内存 (STM)。线程可以通过可以检查冲突的事务来更新共享内存,而不是锁定。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-06-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-08
      • 2011-05-29
      • 1970-01-01
      相关资源
      最近更新 更多