gpt4 book ai didi

c++ - 线程本地获取/释放同步

转载 作者:行者123 更新时间:2023-11-30 02:20:27 32 4
gpt4 key购买 nike

一般来说,加载-获取/存储-释放同步是 C++11 内存模型中最常见的基于内存排序的同步形式之一。这基本上就是互斥锁提供内存排序的方式。加载获取和存储释放之间的“关键部分”始终在不同的观察者线程之间同步,因为所有观察者线程将就获取之后和释放之前发生的事情达成一致。

通常,这是通过读取-修改-写入指令(如比较交换)以及获取屏障来实现的,当进入临界区时,以及在退出临界区时另一个带有释放屏障的读取-修改-写入指令部分。

但在某些情况下,加载获取和发布存储之间可能有类似的临界区[1],只是只有一个线程实际修改了同步变量。其他线程可能读取同步变量,但实际上只有一个线程修改它。在这种情况下,进入临界区时,不需要读-修改-写指令。您只需要一个简单的存储,因为您不会与其他试图修改同步标志的线程竞争。 (这可能看起来很奇怪,但请注意许多无锁内存回收延迟模式,如用户空间 RCU 或基于纪元的回收,使用仅由一个线程写入但由多个线程读取的线程局部同步变量,因此这种情况并不太奇怪。)

所以,当进入临界区时,你可以这样做:

sync_var.store(true, ...);

.... critical section ....

sync_var.store(false, std::memory_order_release);

没有竞争,因为再次强调,当只有一个线程需要设置/取消设置临界区变量时,不需要读取-修改-写入。其他线程可以简单地通过加载获取来读取临界区变量。

问题是,当您进入临界区时,您需要一个acquire 操作 或fence。但是你不需要做一个LOAD,只需要一个STORE。那么,当您真正只需要一个 STORE 时,什么是产生获取订单的好方法呢?我只看到两个真正的选项属于 C++ 内存模型。要么:

  1. 使用 exchange 而不是商店,因此您可以执行 sync_var.exchange(true, std::memory_order_acquire)。这里的缺点是交换是一个更重量级的读取-修改-写入操作,而您真正需要的只是一个简单的存储。
  2. 插入一个“虚拟”加载获取,例如:

    (void)sync_var.load(std::memory_order_acquire);sync_var.store(true, std::memory_order_relaxed);

“虚拟”加载获取似乎更好。据推测,编译器无法优化掉未使用的负载,因为这是一条原子指令,其副作用是与 sync_var 上的释放操作产生“同步”关系。但它看起来也很老套,如果没有评论解释发生了什么,意图就不清楚了。

那么当我们只需要一个简单的存储时,产生获取语义的最佳方法是什么?


[1] 我随意使用术语“临界区”。我不一定是指始终通过互斥访问的部分。相反,我只是指通过获取-释放语义同步内存排序的任何部分。这可能指的是互斥量,也可能只是指 RCU 之类的东西,其中关键部分可以由多个读者同时访问。

最佳答案

您逻辑中的缺陷是不需要原子 RMW,因为临界区中的数据由单个线程修改,而所有其他线程仅具有读取访问权限。
这不是真的;阅读和写作之间仍然需要有明确的顺序。您不希望在另一个线程仍在读取数据时修改数据。因此,每个线程在访问完数据后都需要通知其他线程。

仅使用原子存储进入临界区,无法建立“同步”关系。获取/释放同步基于运行时关系,其中获取方仅在观察到原子加载返回的特定值后才知道同步已完成。这永远不可能通过单个原子存储来实现,因为一个修改线程可以随时更改原子变量 sync_var因此它无法知道另一个线程是否仍在读取数据。

带有“虚拟”load/acquire 的选项也是无效的,因为它无法通知其他线程它想要独占访问。你试图通过使用一个(轻松的)商店来解决这个问题,但是加载和存储是独立的操作,可以被其他线程中断(即多个线程同时访问临界区)。

每个 线程必须使用原子 RMW 来加载特定值,同时更新变量以通知所有其他线程它现在具有独占访问权限(无论是阅读还是写作)。

void lock()
{
while (sync_var.exchange(true, std::memory_order_acquire));
}

void unlock()
{
sync_var.store(false, std::memory_order_release);
}

可以在多个线程同时具有读取访问权限的情况下进行优化(例如,std::shared_mutex)。

关于c++ - 线程本地获取/释放同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49635697/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com