Multithreading 检查同步锁定标志和退出功能的速记?
我试图阻止我的一个函数多次运行,即使是从几个不同的线程调用,但它看起来相当笨拙 以下是我正在做的:Multithreading 检查同步锁定标志和退出功能的速记?,multithreading,concurrency,swift3,grand-central-dispatch,Multithreading,Concurrency,Swift3,Grand Central Dispatch,我试图阻止我的一个函数多次运行,即使是从几个不同的线程调用,但它看起来相当笨拙 以下是我正在做的: func doSomethingOnceAtATime() { var shouldExit = false DispatchQueue(label: "abcxyz123").sync { guard !inProgress else { shouldExit = true; return } inProgress = true }
func doSomethingOnceAtATime() {
var shouldExit = false
DispatchQueue(label: "abcxyz123").sync {
guard !inProgress else { shouldExit = true; return }
inProgress = true
}
guard !shouldExit else { return }
// Do something
}
我必须这样做,因为
sync
块中的return
只退出该闭包,而不退出它所在的函数。有没有更快捷或优雅的方法来实现这一点?第一个问题是以下代码根本不提供同步:
DispatchQueue(label: "abcxyz123").sync { ... }
这将在每次调用时实例化一个新队列。相反,您应该有一个单一串行队列的属性,然后在所有sync
调用中使用该队列:
private let synchronizationQueue = DispatchQueue(label: "abcxyz123")
func someMethodThatNeedsSynchronizedAccess() {
synchronizationQueue.sync { ... }
}
谈到你关于不喜欢在块之前创建局部变量的问题,我赞同这一点。至少,我倾向于将此模式从
doSomethingOnceAtATime
中拉出,并隔离同步逻辑:
class TaskState {
private var inProgress = false
private let queue = DispatchQueue(label: "...")
func attemptSetInProgress() -> Bool {
var succeed = false
queue.sync {
if !inProgress {
succeed = true
inProgress = true
}
}
return succeed
}
func unsetInProgress() {
queue.sync {
inProgress = false
}
}
}
然后,您的dosomethingoncatatime
变得更加直观:
let state = TaskState()
func doSomethingOnceAtATime() {
if !state.attemptSetInProgress() { return }
// Do something
state.unsetInProgress()
}
但这仍然有局部变量(尽管无可否认,封装在更符合逻辑的层次上)。即使这让您感到困扰,我们也可以利用
sync
方法rethrows
这一事实来消除这一问题。所以我们可以做一些类似的事情:
class TaskState {
enum TaskStateError: Error {
case alreadyInProgress
}
enum State {
case inProgress
case notInProgress
}
private var state = State.notInProgress
private let syncQueue = DispatchQueue(label: "sync")
/// Try changing task status, if we can.
///
/// - Note: Throw error if state already "in progress" and trying to change it to "in progress" again.
func change(to newState: State) throws {
try syncQueue.sync {
if state == .inProgress && newState == .inProgress {
throw TaskStateError.alreadyInProgress
} else {
state = newState
}
}
}
}
注意,上面还概括了“状态”(如果您移动到两个以上的状态)
然后你可以做:
let state = TaskState()
func doSomethingOnceAtATime() {
do { try state.change(to: .inProgress) } catch { return }
// Do something
try? state.change(to: .notInProgress)
}
我必须承认,虽然这消除了局部变量,但我个人认为它并不比先前的模式好。但这取决于你