我们可以直接从Swift使用基于C结构的API吗?

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

我从WWDC 2016离开后,了解到我们应该警惕直接从Swift使用基于C的struct API。在Concurrent Programming With GCD in Swift 3中,谈到基于C的锁,它们非常具体:

...在Swift中,由于您拥有整个Darwin模块,因此您实际上会看到基于struct的传统C锁。但是,Swift假定struct的任何内容都可以移动,并且不适用于互斥锁或锁。因此,我们真的不鼓励您使用Swift的此类锁。 ...

...并且,如果您想要某种……看起来像您在C中拥有的锁,那么您必须调用Objective-C,并在Objective-C中引入一个基类,将您的锁作为ivar。

然后您将公开lockunlock方法,以及一个tryLock(如果需要),您可以在对此类进行子类化时从Swift进行调用。 ...

@implementation LockableObject {
    os_unfair_lock _lock;
}

- (void)lock   { os_unfair_lock_lock(&_lock); }
- (void)unlock { os_unfair_lock_unlock(&_lock); }
@end

但是,观看WWDC 2019 Developing a Great Profiling Experience,我注意到作者实际上是直接从Swift使用os_unfair_lock,而没有这个Objective-C包装器,实际上是:

private var workItemsLock = os_unfair_lock()

func subWorkItem(...) {
    ...
    os_unfair_lock_lock(&self.workItemsLock)
    ...
    os_unfair_lock_unlock(&self.workItemsLock)
    ...
}

根据经验,这种直接使用os_unfair_lock似乎可行,但这并不意味着什么。尊重2016年WWDC视频中的警告,我避免直接​​使用Swift的os_unfair_lock

所以,问题是,在这个2019年的示例中,使用此API时他们是否太草率?还是2016年影片的版权声明不正确?还是自Swift 3起就改变了基于C的struct的处理方式,现在使该模式变得安全了?

c swift struct
1个回答
0
投票

使用private var workItemsLock = os_unfair_lock()的API示例可以在运行时公平。

来自C的线程基元需要一个稳定的内存位置,因此要使用它们或直接将其中一个基元作为其成员的另一个结构,必须使用UnsafePointer。这样做的原因是UnsafePointer API一旦分配了一块内存,就表示该内存是稳定的,编译器无法对其进行移动或复制。

如果您像这样更改示例,则现在有效

private var workItemsLock: UnsafeMutablePointer<os_unfair_lock> = {
    // Note, somewhere else this will need to be deallocated
    var pointer = UnsafeMutablePointer<os_unfair_lock>.allocate(capacity: 1)
    pointer.initialize(to: os_unfair_lock())
    return pointer
}()

func subWorkItem(...) {
    ...
    os_unfair_lock_lock(self.workItemsLock)
    ...
    os_unfair_lock_unlock(self.workItemsLock)
    ...
}
© www.soinside.com 2019 - 2024. All rights reserved.