【问题标题】:Fast thread syncronization快速线程同步
【发布时间】:2012-04-28 18:34:21
【问题描述】:

我正在开发一个具有多个线程和一个共享对象的系统。有许多线程经常执行读取操作,但写入操作很少,每天可能 3 到 5 次。

我正在使用 rwlock 进行同步,但是锁获取操作不够快,因为它一直在发生。所以,我正在寻找一种更快的方法。

也许是一种使写入函数原子化或在写入期间查看所有线程的方法。可移植性不是硬性要求,我使用的是带有 GCC 4.6 的 Linux。

【问题讨论】:

  • 了解更多有关您要解决的问题的信息会很有帮助。例如,读者/作者的关键部分有多大。以及线程之间的一致性要求是什么。由于写入如此罕见,线程读取陈旧数据是否重要?根据您正在做的事情,有许多可能的低级优化可能有意义也可能没有意义。
  • 读取陈旧数据没有问题,问题是在写操作时读取数据。

标签: c++ c multithreading pthreads


【解决方案1】:

您是否考虑过将 read-copy-update 与 liburcu 一起使用?这可以让您避免原子操作并在读取路径上完全锁定,但代价是写入速度相当慢。请注意,一些读者可能会在短时间内看到陈旧的数据;如果您需要更新立即生效,它可能不是您的最佳选择。

【讨论】:

  • +1 在库上,但重要的是要注意,如果内核未启用抢占,则只有在读取器路径中才能避免所有成本,这可能是用户的情况,也可能不是。不同的现成 linux 内核启用了抢占,在这些情况下,让编写器内核在内核中等待直到所有其他内核都进行上下文切换的技巧是不够的,必须使用额外的机制。优点是库知道这一点并且已经实现并测试了它。
  • 它可以工作,因为延迟不是问题。我不知道这个库。我会读一读。
【解决方案2】:

您可能想要使用多个对象而不是单个对象。与其实际共享对象,不如创建一个包含对象和原子计数的对象,然后在线程之间共享一个指向该结构的 指针

【假设只有一个写者】每个读者都会得到指针,然后原子地递增计数器并使用对象,读完后原子地递减计数器。作者将创建一个包含原始副本的新对象并对其进行修改。然后执行两个指针的原子交换。现在问题是释放旧对象,这就是为什么你需要读者的数量。作者需要继续检查旧对象的计数,直到所有读者都完成了工作,此时您可以删除旧对象。

如果有多个写入器(即可以有多个线程更新变量),您可以采用相同的方法,但写入器需要对指针进行比较和交换交换。如果更新副本的指针已更改,则写入器重新启动进程(删除它的新对象,再次从指针复制并重试 CAS)

【讨论】:

  • 没错,只有一位作家。你的建议非常聪明。
  • @Renato:我相信建议的解决方案中存在竞争条件,请注意!特别是,一位读者可能已经获得了指针,但还没有增加引用计数。如果此时写入者执行交换并检查引用计数,它将认为没有读取器访问旧对象并认为它可以有效地删除它,从而导致读取器上的未定义行为(访问已删除对象)。我相信可以通过在外部获取引用计数并在获取指针之前增加它来解决这个问题。
  • ... 在单个编写器的情况下,您可能可以使用两个版本(确保编写器在仍有读者使用它时不会更新对象的非活动版本,如果两次写入足够接近以至于访问最旧对象的读取器可能在第二次更新之前尚未完成)。此解决方案具有不同(更安全)的竞争条件,其中读取器可能会在 指针被写入器更新之后增加计数,因此 ti 将增加旧计数,但访问新对象......
  • ...这不是一个问题,因为结果是作者必须等待旧对象的所有读者潜在的一些新对象的读者删除之前的对象,即作者可能需要比需要回收旧对象更长的时间。
  • 我最初明白我应该有一个外部计数器并在之前递增它。那么问题是编写者也必须更新计数器(将其归零)所以,没有同步方法就无法保持共享计数器和指针的一致性。
【解决方案3】:

也许您可以使用自旋锁,线程将忙于等待直到解锁。如果线程没有长时间锁定,它可能比互斥锁更有效,因为锁定和解锁使用更少的指令完成。

spinlock 是 POSIX pthread 的一部分,虽然是可选的,所以我不知道它是否在您的系统上实现。我在 ubuntu 上的 C 程序中使用了它们,但必须使用 -std=gnu99 而不是 c99 进行编译。

【讨论】:

  • 除了我没有尝试过之外,我认为它不会比 rwlock 快,因为 a 在读取时具有大量并行化(>100)并且它不允许读取并行化。
猜你喜欢
  • 2011-01-18
  • 2016-01-05
  • 2019-05-22
  • 1970-01-01
  • 2021-09-14
  • 2012-03-21
  • 2014-04-30
  • 2011-11-01
  • 1970-01-01
相关资源
最近更新 更多