标准说:“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();
答案 0 :(得分:10)
首先,std::atomic<std::thread::id>
是合法的:std::thread::id
必须是可轻易复制的(30.3.1.1p2),符合std::atomic<>
(29.5p1)的要求。
但是,它是一个不透明的类,因此不要求比较相等的对象的位模式相同。
因此,如果您使用compare_exchange_weak
或compare_exchange_strong
,那么对于比较相等的值,它可能会失败。
因此,建议是在循环中使用compare_exchange_weak
,将expected
值作为上一次迭代的结果。
在您的情况下,我从您的循环中解释的语义是:保持循环,而worker_id
是另一个线程的ID,或worker_id
是std::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();
}
}