如何访问 Swift 6 并发安全的静态属性?

问题描述 投票:0回答:1

我的应用程序使用类

A
及其子类
SubA_x
A
有一个静态属性
serialNumber
,仅在子类初始化时由类
A
修改。 它设置一个属性
let name
,以便每个子类都有一个唯一的名称。 这是代码:

class A {
    static var serialNumber = 0
    let name: String

    init( /* some parameters */ ) {
        A.serialNumber += 1
        self.name = "\(A.serialNumber)"
    }
}

final class SubA_1: A {
    init( /* some parameters */ ) {
        super.init( /* some parameters */ )
    }
}

使用 Swift 6 严格的并发检查,初始化

serialNumber
的行给出错误

静态属性“serialNumber”不是并发安全的,因为它是 非隔离的全局共享可变状态

我知道

A
的每个子类都可以从任何线程修改
var serialNumber
,因此数据竞争是可能的。

但是如何以并发安全的方式实现此功能?

我试图通过演员提供

serialNumber

actor SerialNumberManager {
    private var serialNumber = 0
    
    func getNextSerialNumber() -> Int {
        serialNumber += 1
        return serialNumber
    }
}

但是我无法在

getNextSerialNumber()
中调用
init
,除非
init
是异步的。 但是我只能在异步上下文中初始化子类,等等。

我可能可以提供自己的基于 GCD 的同步,但应该有一种方法可以在 Swift 并发中做到这一点。

swift static thread-safety swift-concurrency swift6
1个回答
1
投票

如果您想要线程安全的共享状态,那么

actor
是一种合乎逻辑的方法。不过,如果您想要一个可以从同步上下文调用的管理器,您可以编写自己的管理器,实现您自己的手动同步(使用 GCD 串行队列,或者如下所示,使用锁):

class SerialNumberManager: @unchecked Sendable {
    static let shared = SerialNumberManager()

    private let lock = NSLock()
    private var serialNumber = 0

    private init() { }

    func nextSerialNumber() -> Int {
        lock.withLock {
            serialNumber += 1
            return serialNumber
        }
    }
}

注意,只有当我们实现了手动同步时,我们才会使用

@unchecked Sendable
,就像上面一样。

而且,你可以像这样使用它:

class A {
    let serialNumber = SerialNumberManager.shared.nextSerialNumber()
    let name: String

    init( /* some parameters */ ) {
        self.name = "\(serialNumber)"
    }
}

或者,您可以使用

OSAllocatedUnfairLock
,它已经是
Sendable
:

import os.lock

class A {
    private static let serialNumber = OSAllocatedUnfairLock(initialState: 0)
    let name: String

    init( /* some parameters */ ) {
        let value = Self.serialNumber.withLock { value in
            value += 1
            return value
        }
        self.name = "\(value)"
    }
}

为了完整起见,其他替代方案包括 atomicsUUIDs

© www.soinside.com 2019 - 2024. All rights reserved.