В приведенном ниже примере, если мы игнорируем мьютекс на секунду, копирование может исключить два вызова конструктора копирования.
user_type foo()
{
unique_lock lock( global_mutex );
return user_type(...);
}
user_type result = foo();
Теперь правила для копирования elision не упоминают потоки, но мне интересно, должно ли это действительно происходить через такие границы. В вышеприведенной ситуации конечная копия в логической абстрактной машине межпоточность происходит после выхода мьютекса. Если, однако, копии не указаны, структура данных результата инициализируется в пределах мьютекса, поэтому межпотоковая передача происходит до выхода мьютекса.
Мне еще предстоит подумать о конкретном примере того, как копирование может действительно привести к состоянию гонки, но вмешательство в последовательность памяти похоже на проблему. Может ли кто-нибудь окончательно сказать, что это не может вызвать проблемы, или кто-нибудь может привести пример, который действительно может сломаться?
Чтобы гарантировать, что ответ касается не только специального случая, обратите внимание на то, что копия elision (согласно моему чтению) все еще разрешена, если у меня есть оператор вроде new (&result)( foo() )
. То есть, result
не должен быть объектом стека. user_type
сам может также работать с данными, разделяемыми между потоками.
Ответ. Я выбрал первый ответ как наиболее подходящее обсуждение. В принципе, поскольку стандарт говорит, что это может произойти, программист должен быть осторожным, когда это происходит по границам синхронизации. Нет никаких указаний, является ли это преднамеренным или случайным требованием. Нам все еще не хватает ни одного примера, показывающего, что может пойти не так, так что, возможно, это не проблема в любом случае.