Подтвердить что ты не робот

В чем смысл этой части Стандарта о shared_ptr use_count()?

При попытке обернуть голову вокруг проблемы, показанной в этом вопросе, я обнаружил, что придерживался следующего предложения из [util.smartptr.shared]/4:

[...] Изменения в use_count() не отражают изменений, которые могут приводить к расам данных.

Я не понимаю, как я должен это прочитать и какие выводы я должен сделать. Вот несколько интерпретаций:

  • Вызов use_count() не вводит расы данных (но это должно быть гарантировано только функцией const только этой функции вместе с соответствующими библиотечными гарантиями)
  • На значение, возвращаемое use_count(), не влияет ( "не отражает"?) результат операций, которые требуют атомарности или синхронизации (но каковы эти соответствующие операции?)
  • use_count() выполняется атомарно, но не препятствует переупорядочению процессором или компилятором (т.е. без последовательной согласованности, но тогда почему не упоминается конкретная модель?)

Для меня ни одно из вышеизложенных, похоже, не следует из этого предложения, и я нахожусь в убытке, пытаясь его интерпретировать.

4b9b3361

Ответ 1

Текущая формулировка происходит из библиотеки issue 896, в которой также был рассмотрен вопрос о том, должен ли shared_ptr быть потокобезопасным в том смысле, что различные shared_ptr владеющие один и тот же объект может быть доступен (в частности, скопирован и уничтожен) из отдельных потоков одновременно. Вывод этого обсуждения состоял в том, что shared_ptr должен быть потокобезопасным; механизм, гарантирующий это, заключался в том, чтобы притворяться, что функции-члены shared_ptr имеют доступ только к объекту shared_ptr, а не к его блоку управления на куче:

Для определения наличия гонки данных функции-члены получают доступ и изменяют только те объекты shared_ptr и weak_ptr, а не объекты, на которые они ссылаются.

Здесь "объекты, на которые они ссылаются" означает блок управления.

Однако это вызывает проблему; если мы притворимся, что отдельный shared_ptr, владеющий одним и тем же объектом, не имеет доступа к блоку управления, то, безусловно, use_count() не может измениться? Это исправлено, создав use_count() волшебную функцию, которая производит результат из воздуха:

Изменения в use_count() не отражают изменений, которые могут привести к расам данных.

То есть, use_count() может меняться от одного вызова к другому, но это не означает, что произошла гонка данных (или потенциальная гонка данных). Это, возможно, яснее из предыдущей формулировки этого предложения:

[Примечание: это верно, несмотря на то, что такие функции часто изменяют use_count() --end note]

Ответ 2

Это означает, что код в use_count() либо заблокирован, либо использует мьютексы для блокировки критических разделов. Другими словами, вы можете называть это из потоков, не беспокоясь о состоянии гонки.

Ответ 3

Я думаю, что когда мы добавляем предыдущее предложение, намерение становится немного яснее:

Для определения наличия гонки данных функции-члены должны получать доступ и изменять только сами объекты shared_ptr и weak_ptr, а не объекты, к которым они относятся. Изменения в use_count() не отражают изменений, которые могут приводить к расам данных.

Итак, последнее предложение просто подчеркивает ту же точку, что и первое предложение. Например, если я скопирую shared_ptr, его счетчик использования будет увеличен, чтобы отразить тот факт, что shared_ptr был скопирован, поэтому результат из use_count() будет изменен - ​​но это не разрешено доступ (и, в особенности, не допускается к изменению) объекта pointee, поэтому он никогда не может ввести гонку данных при использовании этого объекта pointee.