I have a function that accesses a critical variable and needs mutually exclusive access to it, but returns via completion handler.
This is what I am currently using to attempt this:
static func getAccessTokenValue(completionHandlerResult : @escaping (_ accesstoken:String) -> ()) {
tokenQ.sync {
let expire_in_str = UserDefaults.standard.value(forKey: "expires_in") as! String
print(expire_in_str)
let accessToken_time = UserDefaults.standard.value(forKey: "access_token_time") as! Date
let todayDate = Date()
let seconds = (Calendar.current as NSCalendar).components(.second, from: accessToken_time, to: todayDate, options: []).second
if seconds! < Int(5) {
print("success")
completionHandlerResult( Constants.Access_Token)
}
else {
refreshLock.wait()
self.renewAccessToken(completionHandler: { accesstokenValue in
tokenQ.sync {
completionHandlerResult(accesstokenValue)
}
})
refreshLock.signal()
}
}
}
The goal is for only one thread to be able to use self.renewAccessToken
at a time. Using DispatchQueue.sync
alone was not accomplishing this so I moved to semaphores but the above code results in a deadlock as it appears that the refreshLock.signal()
has no effect.
self.renewAccessToken
uses alamofire and has another completion handler within it, which is adding to the threading problems.
The main issue I am running into is multiple threads are trying to renew the same token at the same time and once one thread renews the token the other threads keep the old token and their renewal requests are denied because a token can only be renewed once.
What would be the best way to handle this scenario?
Try this:
static func getAccessTokenValue(completionHandlerResult : @escaping (_ accesstoken:String) -> ()) {
tokenQ.sync {
let expire_in_str = UserDefaults.standard.value(forKey: "expires_in") as! String
let accessToken_time = UserDefaults.standard.value(forKey: "access_token_time") as! Date
let todayDate = Date()
let seconds = (Calendar.current as NSCalendar).components(.second, from: accessToken_time, to: todayDate, options: []).second
if seconds! < Int(5) {
completionHandlerResult( Constants.Access_Token)
}
else {
refreshLock.wait()
self.renewAccessToken(completionHandler: { accesstokenValue in
completionHandlerResult(accesstokenValue)
})
refreshLock.signal()
}
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.