NSConditionLock条件锁在开发中几乎很少用到,虽然知道他的作用但是之前并没有碰到一个用它解决问题的场景。
描述如下一个场景:三个异步任务在并发队列中,同时执行一个耗时任务X,当X执行完毕之后会回调一次数据,如何保证调用顺序和回调顺序一致?
eg:ABC三个异步任务依次书写,并发异步下假如实际调用顺序为BCA,希望回调顺序也是BCA,但其实可能A执行X时最先处理完,但不回调,等待BC回调过后再进行回调,即调用顺序为BCA,回调顺序为BCA,且并发。
利用NSConditionLock可以比较方便实现这个效果,思路如下:通过一个容器记录方法的调用顺序,主动解锁第一个调用,第一个调用一次解锁剩下的调用。
前置一个问题,如果我先进行条件解锁,再进行同条件加锁,此处无效,像下面这样
self.conditionLock.unlock(withCondition: 4)
self.conditionLock.lock(whenCondition: 4)
print("aaa")
正文:
变量部分:
var methodIndex : Array<Int> = Array() //标记调用顺序的容器
var methodIndexLock : NSLock = NSLock.init() //给容器读写加锁的互斥锁
var methodCurrnetLock : Int = 0 //当前解锁到的位置
lazy var conditionLock : NSConditionLock = {
return NSConditionLock.init(condition: 0)
}() //条件锁
//并发调用三个异步任务,为了比较直观,我把第一个任务进行延迟
func testConditionLock() {
DispatchQueue.global().asyncAfter(deadline: .now() + 0.5, execute: {
print("第一个任务开始了")
self.someMethod(1) {
print("第一个任务返回了")
}
})
DispatchQueue.global().async {
print("第二个任务开始了")
self.someMethod(2) {
print("第二个任务返回了")
}
}
DispatchQueue.global().async {
print("第三个任务开始了")
self.someMethod(3) {
print("第三个任务返回了")
}
}
//这里备注下:此处是希望解锁第一个加锁的,也就是像上面前置问题那样,使第一把条件锁无效
DispatchQueue.main.asyncAfter(deadline: .now()+1) {
self.conditionLock.unlock(withCondition: self.methodIndex[0])
}
}
//第一个参数只是一个标识,不代表调用顺序
func someMethod(_ actionIndex:Int,callback:()->Void) {
//对容器读写加锁
self.methodIndexLock.lock()
self.methodIndex.append(actionIndex)
self.methodIndexLock.unlock()
let t = Double(arc4random() % 10)
Thread.sleep(forTimeInterval: t) //此处进行休眠,模拟耗时操作
print(actionIndex,t)
self.conditionLock.lock(whenCondition: actionIndex)
callback()
self.methodCurrnetLock += 1
guard self.methodIndex.count > self.methodCurrnetLock else {
return
}
self.conditionLock.unlock(withCondition: self.methodIndex[self.methodCurrnetLock])
print(self.methodCurrnetLock,self.methodIndex)
}