Требования к std :: thread :: id. Можно ли его распылять?

Стандарт гласит: «Объект типа 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();

8

Решение

Во-первых, 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(),

10

Другие решения

Это обсуждалось в 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();
}
}
5

По вопросам рекламы [email protected]