Стандарт гласит: «Объект типа thread :: id предоставляет … одно отдельное значение для всех объектов потока, которые не представляют поток выполнения». Это единственное / отличное значение в отношении operator==
или это фактическое побитово-одиночное / отличное значение?
Причина вопроса: MSVC2012’s std::thread::id::id()
оставляет мусор в одном из своих полей, и он нарушает код, который делает сравнение-обмен на std::atomic<std::thread::id>
(поскольку последнее зависит от побитовых сравнений).
Является std::atomic<std::thread::id>
юридическая конструкция в первую очередь?
РЕДАКТИРОВАТЬ: для справки, код выглядит так:
while( !worker_id.compare_exchange_weak( no_id = thread_id_type(), self_id ) )
sleep();
Во-первых, 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
это идентификатор другого потока, или 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()
,
Это обсуждалось в 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();
}
}