Почему неизменяемый указатель на статическую неизменяемую переменную не Sync?

Статическая глобальная строка C (как в этом ответе) не имеет Sync.

pub static MY_STRING: &'static *const u8
 = "hello" as const *u8;
// TODO: Simple assertion showing it not Sync ;)

Sync описывается как

Точное определение: тип T равен Sync, если &T является потокобезопасным. Другими словами, нет возможности расследований данных при передаче &T ссылок между потоками.

Кажется, что это полностью readonly и имеет статическое время жизни, поэтому почему безопасно передавать ссылку?

1 ответ

Глава Отправить и синхронизировать в Описание Rustonomicon что это означает для типа Send или Sync. В нем упоминается, что:

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

Но это просто задает вопрос; почему *const T не реализует Sync? Почему важны предохранители?

Как раз перед этим, он говорит:

Отправить и синхронизировать также автоматически производные черты. Это означает, что, в отличие от любого другого признака, если тип полностью составлен из типов отправки или синхронизации, то это Send или Sync. Почти все примитивы - "Отправить и синхронизация", и, как следствие, почти все типы, с которыми вы когда-либо взаимодействуете, - "Отправить и синхронизировать".

Это основная причина, по которой raw-указатели не являются Send и Sync. Если вы определили структуру, которая инкапсулирует необработанный указатель, но только выставляете ее как &T или &mut T в struct API, действительно ли вы убедитесь, что ваша структура соблюдает контракты Send и Sync? Если исходные указатели были Send, то Rc также был бы Send по умолчанию, поэтому ему пришлось бы явно отказаться. (В исходном тексте на самом деле есть явный отказ от Rc, но он предназначен только для целей документации, потому что он фактически избыточен.)

[...] они небезопасные черты. Это означает, что они небезопасны для реализации, а другой небезопасный код может предположить, что они правильно реализованы.

ОК, давайте вспомним: они небезопасны для реализации, но они автоматически выводятся. Разве это не странная комбинация? На самом деле, это не так плохо, как кажется. Наиболее примитивными типами, такими как u32, являются Send и Sync. Просто примирить примитивные значения в структуре или перечислении недостаточно, чтобы дисквалифицировать тип для Send или Sync. Поэтому вам нужно создать структуру или перечисление с не Send или не Sync, прежде чем вам нужно написать unsafe impl.

Send и Sync являются маркерными признаками, что означает, что у них нет методов. Поэтому, когда функция или тип помещает привязку Send или Sync в параметр типа, она полагается на тип, чтобы соблюдать конкретный контракт по всему его API. Из-за этого:

Неправильная реализация Send или Sync может вызвать поведение Undefined.

licensed under cc by-sa 3.0 with attribution.