Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/154.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 你能用原子方法写出两个uint64';s_C++_Multithreading_Locking_Atomic - Fatal编程技术网

C++ 你能用原子方法写出两个uint64';s

C++ 你能用原子方法写出两个uint64';s,c++,multithreading,locking,atomic,C++,Multithreading,Locking,Atomic,我有一个问题,我需要能够以原子方式同时更新两个uint64\t。以原子方式编写它们中的每一个都很容易(例如,有两个std::atomic),但这仍然会导致一个更新而另一个不更新的情况。使用锁和互斥锁也很容易实现 但是我想以原子方式编写这两个变量,而不需要任何类型的锁,这样我仍然可以拥有uint64\t类型的成员变量,这样在读取时就没有锁了。这是因为我的用例涉及到读它们很多很多很多次,但是很少写它们(读1x/ms,写1x/5分钟)。可能吗?如果是,怎么做 我认为不可能直接这么做,但你能做的就是用它

我有一个问题,我需要能够以原子方式同时更新两个
uint64\t
。以原子方式编写它们中的每一个都很容易(例如,有两个
std::atomic
),但这仍然会导致一个更新而另一个不更新的情况。使用锁和互斥锁也很容易实现


但是我想以原子方式编写这两个变量,而不需要任何类型的锁,这样我仍然可以拥有
uint64\t
类型的成员变量,这样在读取时就没有锁了。这是因为我的用例涉及到读它们很多很多很多次,但是很少写它们(读1x/ms,写1x/5分钟)。可能吗?如果是,怎么做

我认为不可能直接这么做,但你能做的就是用它来伪装。特别是,您可以使用uint64\U t对的无锁环形缓冲区。在这种配置中,以非原子方式写入环形缓冲区的非活动元素是安全的,因为在写入结束时以原子方式更新“当前值索引”之前,没有人会从环形缓冲区的该元素读取数据(这是可能的,因为索引可以是int32_t)

警告:只有在能够保证在短时间内不会有太多写入值的情况下(其中“太多”表示“超过环形缓冲区中的插槽数”),此技巧才有效。另外,我建议您找一个实现这一点的STM库,而不是自己滚动,因为众所周知,无锁编程很难100%正确完成。

对于标准来说就是这样(我的重点)

std::atomic
模板可以用任何类型的T实例化:

struct Counters { int a; int b; }; // user-defined trivially-copyable type
std::atomic<Counters> cnt;         // specialization for the user-defined type
这是很容易复制的(很容易确认),然后使用
std::atomic

这样,编译器将自动使用无锁更新机制(如果可用)。不需要做任何特殊的事情,只需在必要时使用以下任一选项进行检查

除std::atomic_标志外的所有原子类型都可以使用互斥锁或其他锁定操作来实现,而不是使用无锁原子CPU指令。原子类型有时也允许是无锁的:例如,如果只有一些子体系结构支持对给定类型的无锁原子访问(例如x86-64上的CMPXCHG16B指令),则可能直到运行时才知道原子是否是无锁的

在编译器资源管理器上。正如您所看到的,发出了一个
锁cmpxchg16b
,尽管GCC 7和更高版本只会调用
\uu原子存储\u 16
,其中

在某些平台上,
long double
是128位类型,或者被填充为128位,因此
std::atomic
可能是另一种解决方案,但当然,您需要首先检查它的大小以及它是否无锁

另一种选择是。它还需要检查宏

在某些CPU上,128位SSE操作也是原子操作,不幸的是,无法检查您是否可以使用该操作

另见:

Hmmm。。。。听起来好像你正在寻找错误类型的锁定模式,也许是不可能的C++。如果您使用的是x64 CPU,则如果两个64位值并排且16字节对齐,则可以使用
CMPXCHG16B
指令。可以无锁原子访问的对象取决于硬件。如果硬件不支持128位原子对象,那么您就无法做到这一点。原子模板是消除这种差异的一种方法,使用需要它的硬件上的锁,并在可用的情况下使用硬件支持。@CoryNelson假设它们并排对齐,我将如何使用该指令?我删除了我的答案-它只适用于写入可以原子化的情况-这是我在硬件上学习该技巧的情况。对不起,这个名字只是举个例子,不太重要。OP应该决定最能反映其工作的一个。无论如何,我刚刚编辑了answer-1,在任意类型上实例化
原子
,但没有为该类型提供完全的专门化,这几乎从来都不是您想要的,并且肯定会在任何接触该代码的程序员脸上引起惊讶的表情。但是,请注意,对类型为
std::atomic
的对象进行的原子更新不需要是无锁的。@Comics表示一个简单的结构,它是可复制的,可以与
std::atomic
一起使用。您可以在
std::atomic
文档中看到相同的示例
struct atomic128 {
    uint64_t a1, a2;
};