3 回答
TA贡献1765条经验 获得超5个赞
Kirsteins是正确的,但是您并不总是需要使用调度队列。您可以使用:
objc_sync_enter(array)
// manipulate the array
objc_sync_exit(array)
这应该可以解决问题。为了获得更多好处,您可以创建一个需要线程安全时使用的函数:
func sync(lock: NSObject, closure: () -> Void) {
objc_sync_enter(lock)
closure()
objc_sync_exit(lock)
}
...
var list = NSMutableArray()
sync (list) {
list.addObject("something")
}
请注意,我已更改AnyObject为NSObject。在Swift集合中,类型被实现为structs,并通过value传递,因此我猜想使用方便的函数时,使用通过引用传递的可变集合类会更安全。sync
Swift更新
线程安全访问的推荐模式是使用dispatch barrier:
let queue = DispatchQueue(label: "thread-safe-obj", attributes: .concurrent)
// write
queue.async(flags: .barrier) {
// perform writes on data
}
// read
var value: ValueType!
queue.sync {
// perform read and assign value
}
return value
TA贡献1893条经验 获得超10个赞
我解决此问题的方法是使用串行分派队列,以同步对盒装阵列的访问。当您尝试获取索引值并且队列确实很忙时,它将阻塞线程,但这也是锁的问题。
public class SynchronizedArray<T> {
private var array: [T] = []
private let accessQueue = dispatch_queue_create("SynchronizedArrayAccess", DISPATCH_QUEUE_SERIAL)
public func append(newElement: T) {
dispatch_async(self.accessQueue) {
self.array.append(newElement)
}
}
public subscript(index: Int) -> T {
set {
dispatch_async(self.accessQueue) {
self.array[index] = newValue
}
}
get {
var element: T!
dispatch_sync(self.accessQueue) {
element = self.array[index]
}
return element
}
}
}
var a = SynchronizedArray<Int>()
a.append(1)
a.append(2)
a.append(3)
// can be empty as this is non-thread safe access
println(a.array)
// thread-safe synchonized access
println(a[0])
println(a[1])
println(a[2])
TA贡献1836条经验 获得超13个赞
Kirsteins的答案是正确的,但是为了方便起见,我使用Amol Chaudhari和Rob的建议更新了该答案,他建议使用带有异步屏障的并发队列来允许并发读取但阻止写入。
我还包装了一些对我有用的其他数组函数。
public class SynchronizedArray<T> {
private var array: [T] = []
private let accessQueue = dispatch_queue_create("SynchronizedArrayAccess", DISPATCH_QUEUE_CONCURRENT)
public func append(newElement: T) {
dispatch_barrier_async(self.accessQueue) {
self.array.append(newElement)
}
}
public func removeAtIndex(index: Int) {
dispatch_barrier_async(self.accessQueue) {
self.array.removeAtIndex(index)
}
}
public var count: Int {
var count = 0
dispatch_sync(self.accessQueue) {
count = self.array.count
}
return count
}
public func first() -> T? {
var element: T?
dispatch_sync(self.accessQueue) {
if !self.array.isEmpty {
element = self.array[0]
}
}
return element
}
public subscript(index: Int) -> T {
set {
dispatch_barrier_async(self.accessQueue) {
self.array[index] = newValue
}
}
get {
var element: T!
dispatch_sync(self.accessQueue) {
element = self.array[index]
}
return element
}
}
}
UPDATE 这是相同的代码,为Swift3更新。
public class SynchronizedArray<T> {
private var array: [T] = []
private let accessQueue = DispatchQueue(label: "SynchronizedArrayAccess", attributes: .concurrent)
public func append(newElement: T) {
self.accessQueue.async(flags:.barrier) {
self.array.append(newElement)
}
}
public func removeAtIndex(index: Int) {
self.accessQueue.async(flags:.barrier) {
self.array.remove(at: index)
}
}
public var count: Int {
var count = 0
self.accessQueue.sync {
count = self.array.count
}
return count
}
public func first() -> T? {
var element: T?
self.accessQueue.sync {
if !self.array.isEmpty {
element = self.array[0]
}
}
return element
}
public subscript(index: Int) -> T {
set {
self.accessQueue.async(flags:.barrier) {
self.array[index] = newValue
}
}
get {
var element: T!
self.accessQueue.sync {
element = self.array[index]
}
return element
}
}
}
添加回答
举报