【问题标题】:compare_exchange_strong failing despite data matching expected value尽管数据与预期值匹配,compare_exchange_strong 仍失败
【发布时间】:2016-02-21 09:14:13
【问题描述】:

问题在于 compare_exchange_strong 返回 false,尽管基础数据等于 expected。例如:

std::atomic<data> ptr;
...
auto ptr_data = ptr.load();
bool cmp_result = memcmp(&ptr_data, &expected, sizeof(ptr_data));
bool cas_result = ptr.compare_exchange_strong(expected, desired);
assert(cas_result || !cmp_result);

data 是一个 128 位的 POD。 ptr.is_lock_free() 返回真。这是以单线程方式测试的。 cas_result 始终为假,cmp_results 始终为真。

使用 Intel 的 C++ 编译器,版本 16 更新 2 完成编译。在 Linux 上,libstdc++ 版本 5.3.1。 64 位二进制。
与在 Windows 上编译时可以正常工作的代码完全相同,具有相同的 ICC16,但作为 32 位代码。这让我相信这是 stdlib 实现的怪癖。

谢谢

【问题讨论】:

  • 那是我的错,请忽略。该示例是从内存中编写的。这些值在 CAS 之前由调试器进行比较。已更新。
  • 嗯,好的。该库的实现只是遵循编译器内在函数__atomic_compare_exchange,所以我怀疑这是一个库问题。
  • 我认为您错误地调用了memcmp - 参数已经是指向比较数据的指针,为什么要将它们作为指针传递?

标签: c++ c++11 icc stdatomic


【解决方案1】:

我在使用的结构上也遇到过这种情况。我认为这是由于对齐问题而插入的填充位以及 compare_exchange 对两个值进行按位比较这一事实引起的。

在我的机器上,字/指针大小是 8 个字节,而我的结构是这样的:

struct s {
    int i;
    void *ptr;

};

它只使用 12 个字节来表示它的内容(ptr 是 8 个字节,int 是 4 个),但它的大小是 16 个字节(sizeof(s) == 16)。我所做的是将结构更改为:

struct s {
    long long i;
    void *ptr;
};

因为在我的机器上 long long 是 8 个字节,所以这个版本有 16 个字节大小,它们都用来表示实际值(没有填充位)。

看了this的回答才看到问题,可能会更详细。

【讨论】:

  • 我认为 memcmp supposed 也是完整对象表示的按位比较,包括填充。但我认为问题在于 ICC 将 memcmp 优化为仅比较相等的值。建议:对于 32 位或 64 位模式,使用 intptr_tptrdiff_t 获取与指针一样宽的 int。所以它总是两个大小相等的成员,如果你编译为 32 位或 64 位 ILP32 ABI,如 Linux x32 或 AArch64 的 ILP32,则只能是 8 个字节。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-09
  • 2016-10-21
  • 2019-07-03
  • 1970-01-01
  • 1970-01-01
  • 2018-10-09
相关资源
最近更新 更多