将多个值打包到一个原子中的标准化方法

Posted

技术标签:

【中文标题】将多个值打包到一个原子中的标准化方法【英文标题】:Standardized ways to pack multiple values into one atomic 【发布时间】:2017-08-06 09:49:54 【问题描述】:

假设我有两个 int32 类型的原子变量,我可以选择将它们表示为 std::atomic<int64> both,并为我的第一个 int 保留前 32 位,为我的第二个 int 保留最后一个。

这似乎在 x64 架构上节省了大量空间和时间,更不用说它允许各种黑魔法,因为可以抽象各种操作并使它们成为原子:

first == a && second ==b

变成

both == ( int64(a) + int64(b) << 32 )
//Or some such... I'm not 100% sure this is correct but you get the idea

我看到的这个技巧的一个问题是,我并不是特别喜欢在位级别进行操作,而且 C++ 在位级别的操作方面也不是很友好,尤其是当您尝试完成更复杂的操作时操作或将两个以上的变量(例如两个数字和几个布尔值)打包到同一个原子中。

所以我想知道是否有一种标准化的方式来应用这种技巧。一种模式甚至标准功能,在看到时很容易被其他编码人员识别并且更易于实施者使用?同样,这种模式是否有用到足以保证这样的标准化,或者与它可能带来的可能的烦恼和 UB 相比,它的用处是否很快就会过时?

【问题讨论】:

您在寻找位域吗? 整数的用途是什么?它们可以存储在std::pairstd::tupple 中吗?一个结构?上课? 哦,还有最重要的选项:什么都不做! 虽然它可能会在这里和那里节省一些字节,但使用打包在一个单个变量意味着节省的内存将被处理这些值所需的更多操作所抵消,从而导致性能下降。更不用说代码将更难阅读、理解和最重要的维护。打包这些值对我来说似乎是一个过早的优化,而且几乎总是很糟糕。 您还应该检查编译器在将两个 32 位值存储在(64 位)结构中时所做的工作。也许它已经可以原子地加载和存储结构:godbolt.org/g/pZ7jQf @ Bo Persson ...好吧,我完全不知道将原子模板放置在任何 64 位值上是可能的。事后看来确实有道理,谢谢。 【参考方案1】:

使用原子绕过 Read-Then-Write 的方法是使用循环:

void setBit(atomic<int64_t>& bitset, int bit)

  int64_t val = 1LL << bit;
  int64_t prev = bitset;
  while ((!(bitset & val)) && 
         !bitset.compare_exchange_weak(prev, (prev | val))
    ;

您可以扩展此方法以创建通用的按位运算函数

【讨论】:

这并不是我真正想要的,尽管这个问题可能措辞不当。我正在寻找的更类似于@Bo Persson 的答案,即无需对位进行直接操作且无需执行额外操作(无论如何都会破坏此优化的全部要点)来操作值的方法。

以上是关于将多个值打包到一个原子中的标准化方法的主要内容,如果未能解决你的问题,请参考以下文章

将单个 HTTP 标头的多个值添加到请求或响应的标准

如何将一个Java项目打包打成多个Jar包

VBA按多个标准剪切和粘贴行

VLOOKUP 具有多个标准,在一个单元格中返回值

如何使用 Unix(或 Windows)中的(最好是未命名的)管道将一个进程的标准输出发送到多个进程?

常用标准化方法