Является ли копирование при записи в Swift потокобезопасным?

Сделать массив или словарь типом значения по определению, но затем фактически скопировать его только тогда, когда одна ссылка на него пытается изменить его, — прекрасная идея, но это заставляет меня насторожиться в многопоточном/многопотоковом контексте. Мне нужно знать:

Является ли возможность Swift копирования при записи потокобезопасной? например: если я создаю массив в одной очереди и передаю его в другую очередь, безопасно ли для одной из очередей изменять его, в то время как другая может его читать или изменять? Поскольку по определению копирование было сделано, когда ссылка на массив была передана во вторую очередь, можем ли мы предположить, что инженеры Swift поступили правильно и реализовали копирование при записи безопасным для очередей способом?

Я нашел это старое обсуждение этого, которое кажется авторитетным, но в обоих направлениях! https://developer.apple.com/forums/thread/53488

Некоторые заслуживающие доверия голоса говорят, что это потокобезопасно, другие говорят, что это не так. Я предполагаю, что это может быть потому, что в какой-то ранней версии Swift этого не было, а, возможно, в Swift 5 это так. Кто-нибудь здесь точно знает Swift 5?

Вот пример кода, иллюстрирующий проблему:

func func1()
{
    var strings1: [String] = ["A", "B", "C"]
    var strings2: [String] = strings1   // array not actually copied
    queue.async()
    {
        strings2.append("D")
    }

    print(strings1[0])    // is this reference thread-safe?
    strings1.append("E")  // is this modification thread-safe?
}

person Christopher Schardt    schedule 14.08.2020    source источник
comment
Я не голосовал против, а рекомендовал: если вы можете основывать свой вопрос на практических фрагментах кода, а не на мнениях в каких-то дебатах в другом месте, у вас меньше шансов получить отрицательные голоса.   -  person Rob    schedule 14.08.2020
comment
Swift всегда считал гонки чтения/записи и записи/записи одной и той же переменной неопределенным поведением. SE-0176 Принудительный монопольный доступ к памяти.. насколько я помню, swift изначально был < i>не потокобезопасный преднамеренно по замыслу.   -  person Asperi    schedule 15.08.2020
comment
Думаю, я что-то здесь не понимаю: зачем кому-то голосовать против вопроса? Я задал не только хороший вопрос, но и ответ на него касается ВСЕХ, кто программирует на Swift с несколькими очередями. Нет, я не включал пример кода. Почему? Потому что легко представить, о чем я говорю, если вы вообще знакомы с программированием с несколькими очередями. Да, я дал ссылку на другое обсуждение. Это проблема? Я сделал это, потому что это дало заслуживающие доверия, но противоречивые ответы на мой вопрос, который я нашел интересным. Почему кто-то обижается на это?   -  person Christopher Schardt    schedule 16.08.2020
comment
Аспери, вопрос не в том, могут ли быть две очереди, работающие с точно такой же переменной, как с одной и той же глобальной переменной. Могут ли они работать с копиями одного и того же значения. Ответ на это прост, если значение является скалярным типом: Да! Это также просто, если вы используете язык, который действительно создает копии значения массива/словаря, когда вы передаете значение в функцию или присваиваете его новой переменной. Проблема в том, что Swift говорит, что КОНЦЕПТУАЛЬНО такие значения копируются во время назначения, но на самом деле копия делается позже. Является ли эта копия безопасной для очереди?   -  person Christopher Schardt    schedule 16.08.2020
comment
Я знаю, что Роб копается в этом вопросе гораздо глубже и, надеюсь, найдет что-то более определенное, но COW никак не может быть потокобезопасным. В этом весь смысл типов значений в Swift. Они были бы бесполезны, если бы не были потокобезопасными. Я полностью согласен с Кристофером в том, что комментарии эскимосов очень удивительны, и я хотел бы, чтобы у меня была ссылка, которая определенно говорила бы, что этот очевидный факт верен. (Боюсь, что это настолько очевидно, что никто не счел необходимым явно задокументировать это. Это не делает вопрос недействительным. Это хороший вопрос.)   -  person Rob Napier    schedule 17.08.2020


Ответы (1)


Хорошо, поскольку никто из Apple/Swift Inc не отвечает, я рискну предположить:

Я предполагаю, что когда у вас есть значение массива в swift, это ссылка на ссылку на NSArray или NSMutableArray. (Да, я знаю, что это верно только для объектов класса, но давайте не будем усложнять.) Без присвоения нового значения вашему значению массива можно сделать ссылку более низкого уровня для ссылки на другой NS-объект простым операции с ним, такие как добавление или обрезка. Существует также счетчик ссылок, прикрепленный к базовому NS-объекту.

Когда вы изменяете массив, первое, что делает Swift, — это проверяет, является ли ссылка Swift единственной ссылкой на базовый NS-объект. Если это так, NSArray при необходимости преобразуется в NSMutableArray, и выполняется модификация. Если нет, то NSArray копируется в NSMutableArray, происходит модификация, и ссылка Swift более низкого уровня изменяется так, чтобы она указывала на новый NS-объект.

Если это действительно тот процесс, которому следует копирование при записи, и если мы можем предположить, что механизм подсчета ссылок и система сохранения/освобождения являются потокобезопасными, то я бы сказал, что копирование при записи является потокобезопасным. Даже если другой поток выполняет модификацию, как описано выше, поскольку он модифицирует копию, которую только что сделал ИТ-специалист, он вообще не должен изменять исходный массив.

Если вы точно знаете, что все, что я написал, неверно, или если вы знаете другую информацию, относящуюся к этой проблеме, ПОЖАЛУЙСТА, поделитесь ею здесь. Эта проблема слишком важна, чтобы оставить ее в статусе «Должна просто работать». :-)

person Christopher Schardt    schedule 22.08.2020
comment
Всегда есть компромиссы. Я не знаю, но это может быть потокобезопасным, только если вы не оптимизируете двоичный файл выше определенного уровня или он не находится под большой нагрузкой. Я знаю, что быстрая строка достаточно быстра, поэтому держу пари (извините), что она не является потокобезопасной при изменении. - person 9dan; 22.08.2020