Site icon image技術メモ

[SE-0371]Isolated synchronous deinit

参照


提案概要

  • GlobalActorに隔離されたクラスのdeinitに対して isolated を付与することで、deinit内部の処理をActor隔離する

なぜ必要か

  • deinitをActor隔離できないことから、不要なワークアラウンドが必要な場合があり、利便性を損ねているため

どのように使うか

  • 以下例のように、明示的に isolatedを付与する
class NonSendableAhmed { 
  var state: Int = 0
}

@MainActor
class Maria {
  let friend: NonSendableAhmed

  init() {
    self.friend = NonSendableAhmed()
  }

  init(sharingFriendOf otherMaria: Maria) {
    // While the friend is non-Sendable, this initializer and
    // and the otherMaria are isolated to the MainActor. That is,
    // they share the same executor. So, it's OK for the non-Sendable value
    // to cross between otherMaria and self.
    self.friend = otherMaria.friend
  }

  isolated deinit {
    // Used to be a potential data race. Now, deinit is also
    // isolated on the MainActor, so this code is perfectly 
    // correct.
    friend.state += 1
  }
}

func example() async {
  let m1 = await Maria()
  let m2 = await Maria(sharingFriendOf: m1)
  doSomething(m1, m2)
} 

いつ使うか

  • deinit内部で、外部にNon-Sendableな値をスレッドセーフな状態を保って操作したい場合

その他備考