为了账号安全,请及时绑定邮箱和手机立即绑定

在Swift中创建线程安全数组

在Swift中创建线程安全数组

茅侃侃 2019-10-06 14:05:11
我在Swift中遇到了线程问题。我有一些对象的数组。通过委托,该类大约每秒钟获取一个新对象。之后,我必须检查对象是否已经在数组中,因此我必须更新对象,否则必须删除/添加新对象。如果添加新对象,则必须首先通过网络获取一些数据。这是通过块进行的。现在我的问题是,我该如何同步这些任务?我试过了dispatch_semaphore,但是这个阻塞了UI,直到阻塞完成。我还尝试了一个简单的bool变量,该变量检查当前是否正在执行该块,并同时跳过compare方法。但是两种方法都不理想。管理阵列的最佳方法是什么,我不想在阵列中有重复的数据。
查看完整描述

3 回答

?
POPMUISE

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


查看完整回答
反对 回复 2019-10-06
?
白猪掌柜的

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])


查看完整回答
反对 回复 2019-10-06
?
开心每一天1111

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

    }

}

}


查看完整回答
反对 回复 2019-10-06
  • 3 回答
  • 0 关注
  • 912 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信