8

该标准说:“thread::id 类型的对象为所有不代表执行线程的线程对象提供......一个不同的值”。这是关于 的单个/不同值operator==,还是实际的按位单个/不同值?

问题的原因:MSVC2012std::thread::id::id()在它的一个字段中留下了垃圾,并且它破坏了在 an 上进行比较交换的代码std::atomic<std::thread::id>(因为后者取决于按位比较)。

首先是std::atomic<std::thread::id>合法的构造吗?

编辑:作为参考,代码如下:

while( !worker_id.compare_exchange_weak( no_id = thread_id_type(), self_id ) )
    sleep();
4

2 回答 2

11

首先std::atomic<std::thread::id>是合法的:std::thread::id要求可平凡复制(30.3.1.1p2),满足std::atomic<>(29.5p1)的要求。

但是,它是一个不透明的类,因此不要求比较相等的对象的位模式相同。

因此,如果您使用compare_exchange_weakor compare_exchange_strongthen 它可能会因比较相等的值而失败。

因此,建议是compare_exchange_weak在循环中使用,expected值保留为上一次迭代的结果

在您的情况下,我从您的循环中解释的语义是:保持循环同时worker_id是另一个线程的 ID,或者worker_idstd::thread::id但交换失败。您可以通过以下方式实现此目的:

no_id=std::thread::id();
while((no_id!=std::thread::id()) ||
      !worker_id.compare_exchange_weak( no_id, self_id ) ){
    if(no_id!=std::thread::id()) no_id=std::thread::id();
    sleep();
}

或者

no_id=std::thread::id();
while(!worker_id.compare_exchange_weak(
          (no_id!=std::thread::id())?(no_id=std::thread::id())?no_id, self_id ) )
    sleep();

即只有在不是时才更改no_id值。 std::thread::id()

于 2012-10-03T10:37:27.927 回答
5

这在LWG924中进行了讨论。本质上,您不能使用compare_exchange_strong,但您应该能够在循环中使用 compare_exchange_weak,例如

expected = current.load();
do {
  desired = function(expected);
} while (!current.compare_exchange_weak(expected, desired));

编辑:无条件重置值会破坏循环的目的 - 基于提供的代码,我认为最好的解决方案是:

no_id = std::thread::id();
while( !worker_id.compare_exchange_weak( no_id, self_id ) )
{
  if (no_id != std::thread::id())
  {
    sleep();
    no_id = std::thread::id();
  }
}
于 2012-10-03T08:42:46.340 回答