std :: thread :: id的要求。可以雾化吗?

时间:2012-10-03 07:11:41

标签: c++ multithreading c++11 atomic language-lawyer

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

问题的原因:MSVC2012的std::thread::id::id()在其中一个字段中留下了垃圾,它打破了在std::atomic<std::thread::id>上进行比较交换的代码(因为后者依赖于按位比较)。 / p>

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

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

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

2 个答案:

答案 0 :(得分:10)

首先,std::atomic<std::thread::id>是合法的:std::thread::id必须是可轻易复制的(30.3.1.1p2),符合std::atomic<>(29.5p1)的要求。

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

因此,如果您使用compare_exchange_weakcompare_exchange_strong,那么对于比较相等的值,它可能会失败。

因此,建议是在循环中使用compare_exchange_weakexpected值作为上一次迭代的结果

在您的情况下,我从您的循环中解释的语义是:保持循环,而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()值。

答案 1 :(得分: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();
  }
}