相关疑难解决方法(0)

为什么volatile在多线程C或C++编程中不被认为有用?

正如我最近发布的这个答案所示,我似乎对volatile多线程编程环境中的实用程序(或缺乏实用程序)感到困惑.

我的理解是这样的:每当一个变量可以在访问它的一段代码的控制流之外被改变时,该变量应该被声明为volatile.信号处理程序,I/O寄存器和由另一个线程修改的变量都构成这种情况.

所以,如果你有一个全局int foo,并且foo由一个线程读取并由另一个线程原子设置(可能使用适当的机器指令),则读取线程看到这种情况的方式与它看到由信号处理程序调整的变量或由外部硬件条件修改,因此foo应该声明volatile(或者,对于多线程情况,使用内存隔离负载访问,这可能是一个更好的解决方案).

我怎么错,哪里错了?

c c++ multithreading volatile c++-faq

159
推荐指数
8
解决办法
6万
查看次数

什么时候使用volatile多线程?

如果有两个线程访问全局变量,那么许多教程都说使变量volatile变为阻止编译器将变量缓存在寄存器中,从而无法正确更新.但是,访问共享变量的两个线程是通过互斥锁来调用保护的东西不是吗?但是在这种情况下,在线程锁定和释放互斥锁之间,代码处于一个关键部分,只有那个线程可以访问变量,在这种情况下变量不需要是volatile?

那么多线程程序中volatile的用途/目的是什么?

c++ concurrency multithreading atomic volatile

121
推荐指数
3
解决办法
5万
查看次数

在实践中,无锁原子是否无地址?

Boost.Interprocess是一个很棒的库,可以简化不同进程之间共享内存的使用.它提供互斥锁,条件变量和信号量,允许在从共享内存中写入和读取时进行同步.

但是,在某些情况下,这些(相对)性能密集型同步机制不是必需的 - 原子操作足以满足我的用例,并且可能会提供更好的性能.

不幸的是,Boost.Interprocess似乎没有原子.


C++标准库提供了std::atomic类模板,它封装了操作需要是原子的对象,还具有测试原子操作是否无锁的功能.但它也不要求无锁原子也不需要地址:[atomics.lockfree]/4只是鼓励无锁操作无地址,这与cppreference一致.

我想不出为什么会以非地址方式实现无锁原子的任何理由.在我看来,以无地址的方式实现无锁原子相当容易.

因为在使用原子而不是互斥体(来自Boost.Interprocess)时我会获得显着的性能优势,所以在这里折扣标准兼容性并将std::atomic对象存储在共享内存中似乎很诱人.


这个问题分为两部分:

  1. 在实践中,CPU是否以无地址方式实现无锁原子?(我只关心用于运行现代桌面和移动操作系统的CPU(例如Windows,MacOS,Linux,Android,iOS),但不关心嵌入式系统)
  2. 为什么实现使用无锁地址的无地址原子?

c++ atomic shared-memory lock-free c++17

7
推荐指数
1
解决办法
660
查看次数

应该使用什么 C++ 构造来访问与另一个进程共享的内存

C++ 代码应该如何访问与另一个应用程序共享的内存,例如通过memmapd 文件?选项似乎是:

  1. 常规原始访问,例如int* p = ...address of shared memory...; *p = 5; *p. 这似乎是不安全的,因为允许编译器假设 的内容p是稳定的,但事实并非如此。
  2. 考虑这些操作的一种方法是它们是另一个进程的输入/输出,因此(至少在旧版本的 C++ 中)应该实现的方式似乎是使用volatile.
  3. 由于现代 C++ 包含内置的原子操作,另一种选择是使用原子。在实践中,编译器似乎并没有对这些操作做太多优化,但不清楚是否被标准禁止。

从实验来看,似乎 2 和 3 都在实践中工作(2 没有正确处理弱记忆的复杂性),但是否符合标准?我是否需要使用组合,即访问atomic<volatile int>

c++ language-lawyer c++14 c++17

5
推荐指数
0
解决办法
93
查看次数

在同一地址上具有 2 个 std::atomic 变量的两个不同进程?

我阅读了 C++ 标准 (n4713) 的 § 32.6.1 3:

无锁的操作也应该是无地址的。也就是说,通过两个不同地址对同一内存位置的原子操作将进行原子通信。实现不应依赖于任何每个进程的状态。此限制允许通过多次映射到进程的内存和在两个进程之间共享的内存进行通信。

所以听起来可以在同一内存位置执行无锁原子操作。我想知道怎么做。

假设我在 Linux 上有一个命名的共享内存段(通过 shm_open() 和 mmap())。例如,如何对共享内存段的前 4 个字节执行无锁操作?

起初,我以为我可以只reinterpret_cast指向std::atomic<int32_t>*. 但后来我读到了这个。它首先指出 std::atomic 可能没有相同大小的 T 或对齐:

当我们设计 C++11 原子时,我误以为可以使用诸如

int x; reinterpret_cast<atomic<int>&>(x).fetch_add(1);
Run Code Online (Sandbox Code Playgroud)

如果 atomic 和 int 的表示不同,或者它们的对齐方式不同,这显然会失败。但我知道这在我关心的平台上不是问题。而且,在实践中,我可以通过在编译时检查大小和对齐方式匹配来轻松测试问题。

Tho,在这种情况下对我来说很好,因为我在同一台机器上使用共享内存,并且在两个不同的进程中投射指针将“获取”相同的位置。但是,文章指出编译器可能不会将强制转换的指针视为指向原子类型的指针:

然而,这不能保证是可靠的,即使在人们可能期望它工作的平台上,因为它可能会混淆编译器中基于类型的别名分析。编译器可能会假设 int 也不会作为atomic<int>. (见 3.10,[Basic.lval],最后一段。)

欢迎任何输入!

c++ shared-memory c++11 stdatomic

3
推荐指数
1
解决办法
871
查看次数