Действительно ли тип значения безопасен в нескольких потоках? - PullRequest
0 голосов
/ 10 января 2019

Apple сказала: «Если вы используете тип значения, вы можете безопасно передавать копии значений между потоками без синхронизации». Но в последнее время я видел сбой параллелизма, противоречащий руководству Apple.

Я видел https://developer.apple.com/swift/blog/?id=10 и руководство Apple, в котором говорилось, что «тип значения безопасен в многопоточности», поэтому я подумал: «Тип значения является атомарным!» но недавно я увидел сбой параллелизма в приведенном ниже коде.

class ClassB: NSObject {

   func readSomeValue() {
      print(classA.someValue)
   }

   let classA = ClassA()

}

class ClassA: NSObject {

  private(set) var someValue: StructA? {
    didSet{
      if oldValue != self.someValue { self.someFunction(self.someValue) }
    }
  }

  private func modifySomeValue(_ newValue: StructA) {
    self.someValue = newValue
  }
}

struct StructA {
  var a: Double
  var b: String?
}

происходит сбой параллелизма при выполнении readSomeValue () в потоке 1 и выполнении modifySomeValue () в потоке 2. Почему происходит сбой параллелизма? Тип значения не безопасен в многопоточности?

1 Ответ

0 голосов
/ 10 января 2019

Пара наблюдений:

  1. Это запись в блоге говорит:

    Важно, что вы можете безопасно передавать копии значений между потоками без синхронизации.

    Рабочее слово здесь - «копии».

    Но в вашем примере вы не передаете копии объекта типа значения в разные потоки. Вы разделяете один экземпляр объекта ссылочного типа, class, между потоками. Конечно, ваш ссылочный тип имеет свойство типа значения, но это не меняет того факта, что вы совместно используете один экземпляр экземпляра объекта ссылочного типа между потоками. Вам нужно будет вручную синхронизировать взаимодействие с этим объектом и его свойствами, чтобы обеспечить безопасность потоков.

  2. Можно утверждать, что многие дискуссии вводят читателей в заблуждение, полагая, что типы значений Swift всегда используют семантику копирования (или копирования при записи) и, следовательно, всегда пользуются этой функцией безопасности потоков. Но вы должны быть осторожны, потому что есть несколько примеров, когда вы не получаете семантику копирования. Ваш пример наличия свойства value-type в объекте ссылочного типа - один из примеров.

    Другим примером является случай, когда вы не используете замыкание «захват списков» . Например, следующее не является потокобезопасным, поскольку использует один и тот же экземпляр типа значения в нескольких потоках:

    var object = StructA(a: 42, b: "foo")
    DispatchQueue.global().async {
        print(object)
    }
    object.b = "bar"
    

    Но, добавив список захвата, глобальная очередь будет иметь свою собственную копию объекта, восстанавливая это взаимодействие с потоками для безопасности потоков, поскольку каждый поток имеет свою собственную копию рассматриваемого объекта:

    var object = StructA(a: 42, b: "foo")
    DispatchQueue.global().async { [object] in
        print(object)
    }
    object.b = "bar"
    
  3. Да, вы можете написать потокобезопасный код, если вы: (а) используете типы значений; и (б) разослать копии этих типов значений. Но это не имеет ничего общего с атомарностью. Итог, переменные Swift не являются атомарными.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...