我对互斥进行了一些研究,发现了以下Swift代码:
class Lock {
private var mutex: pthread_mutex_t = {
var mutex = pthread_mutex_t()
pthread_mutex_init(&mutex, nil)
return mutex
}()
func someFunc() {
pthread_mutex_lock(&mutex)
defer { pthread_mutex_unlock(&mutex) }
...
}
}
该代码在闭包中定义并初始化pthread_mutex_t,然后将返回的值分配给类属性。然后,它在几个功能中进行锁定和解锁,如图所示。
由于还应该调用pthread_mutex_destroy,这意味着互斥体内正在发生某种分配,这种分配可能引用也可能不引用原始值的地址。
实际上,互斥锁在一个地方初始化,然后存储在另一个地方。
问题是这样做是否安全或正确?
如果互斥初始化器需要参数怎么办?
private var mutex: pthread_mutex_t = {
var recursiveMutex = pthread_mutex_t()
var recursiveMutexAttr = pthread_mutexattr_t()
pthread_mutexattr_init(&recursiveMutexAttr)
pthread_mutexattr_settype(&recursiveMutexAttr, PTHREAD_MUTEX_RECURSIVE)
pthread_mutex_init(&recursiveMutex, &recursiveMutexAttr)
return recursiveMutex
}()
后一种方法让我觉得肯定是不正确的,因为当闭包崩溃时,其地址被传递到互斥对象中的属性存储将消失。
事实并非如此,此代码已损坏。
为了工作,pthread_mutex_t
需要在类实例中原位初始化,并且永远不要复制出去。该类将需要公开锁/解锁方法,该方法对实例变量进行适当的操作。
值类型
注意,
pthread_mutex_t
、pthread_rwlock_t
和os_unfair_lock
是值类型,而不是引用类型。这意味着,如果你在它们上使用=,你就复制了一个。这很重要,因为这些类型无法复制!如果您复制pthread类型之一,则该副本将不可用,并且在尝试使用时可能会崩溃。
——作者Mike Ash,周五问答;A 2017-10-27:Locks,Thread Safety,and Swift:2017版
结账https://cocoawithlove.com/blog/2016/06/02/threads-and-mutexes.html
以下是pthread_mutex_t
在Swift中的用法示例:https://github.com/mattgallagher/CwlUtils/blob/0bfc4587d01cfc796b6c7e118fc631333dd8ab33/Sources/CwlUtils/CwlMutex.swift#L60-L105