Ответ 1
Так как std::get
не имеет явных инструкций в спецификации о свойствах рассылки данных, мы возвращаемся к по умолчанию, указанному в [res.on.data.races]. В частности, параграфы 2 и 3 рассказывают историю:
Стандартная библиотека библиотеки С++ не должна прямо или косвенно обращаться к объектам (1.10), доступным для потоков, отличных от текущего потока, если прямо или косвенно обращаться к объектам через аргументы функций, включая
this
.Стандартная библиотечная функция AС++ не должна прямо или косвенно изменять объекты (1.10), доступные для потоков, отличных от текущего потока, если прямо или косвенно обращаться к объектам через аргументы функции
const
, включаяthis
.
Они обеспечивают защиту от расчётов данных только для использования, которые не являются одним и тем же объектом, предоставленным аргументами функции. Параметр шаблона технически не является аргументом функции, поэтому он не подходит.
В вашем случае несколько потоков передают один и тот же объект различным вызовам get
. Поскольку вы передаете параметр не const
, get
будет считаться изменяющим его аргумент tuple
. Поэтому вызов get
на том же объекте считается модификацией объекта из нескольких потоков. И поэтому его вызов может легально спровоцировать гонку данных на tuple
.
Хотя технически говоря, он просто извлекает подобъект из tuple
и поэтому не должен мешать самому объекту или его другим подобъектам. Стандарт этого не знает.
Однако, если параметр был const
, то get
не считается спровоцировать гонку данных с другими вызовами const
на get
. Это просто просмотр одного и того же объекта из нескольких потоков, что разрешено в стандартной библиотеке. Это спровоцировало бы гонку данных с использованием const
не const
или с другими не const
использованием объекта tuple
. Но не с его использованием const
.
Таким образом, вы можете "получить доступ" к ним, но не "изменять" их.