In the Foundation framework, NSLock mutexes, NSCondition variables, NSConditionLock conditionlocks, and NSRecursiveLock recursive locks are provided. These locks are based on the POSIX standard interface pthread_MUtex, pthread_cond, add object-oriented encapsulation. So performance is definitely not as fast as using pthread_mutex and pthread_cond directly. Now let’s understand how they work and how they work.
NSLock
NSLock is a mutex provided by the Foundation framework that uses POSIX pthread_mutex. Common apis include:
Open func 'try' () -> Bool // Keep trying to lock in the specified time, Open func lock(before LIMIT: Date) -> BoolCopy the code
It’s also very simple to use.
///swift public func test_lock() { NSLog("start") self.lock = NSLock() for i in 1... 5 { DispatchQueue.global(qos: .default).async { self.lock?.lock(before: Date().advanced(by: 100)) sleep(5) NSLog("\(i):"+Thread.current.description); self.lock? .unlock() } } NSLog("end") }Copy the code
use mutex
In the Swift Foundation source nslock. Swift file, find the following code (extracted some key code) :
private typealias _MutexPointer = UnsafeMutablePointer<pthread_mutex_t> private typealias _RecursiveMutexPointer = UnsafeMutablePointer<pthread_mutex_t> private typealias _ConditionVariablePointer = UnsafeMutablePointer<pthread_cond_t> open class NSLock: NSObject, NSLocking { internal var mutex = _MutexPointer.allocate(capacity: 1) public override init() {// Initialize the mutex, Pthread_mutex_init (mutex, Nil)} open func lock() {pthread_mutex_lock(mutex)} open func unlock() {// Use mutex to unlock pthread_mutex_unlock(mutex) } }Copy the code
NSCondition
NSCondition is a condition variable provided by Foundation framework, and is also a mutex. The underlying is the encapsulation of POSIX pthread_cond condition variable and Pthread_mutex mutex. Pthread_mutex ensures thread-safe access to pthread_cond and lock() operations. The pthread_cond is a semaphore that tells other threads to resume or suspend the current thread. Common apis include:
Func unlock() // suspend current thread until signal open func wait() // Suspend current thread, Signal open func wait until limit: Date) -> Bool Open Func signal(); open func signal();Copy the code
It’s also very simple to use.
///swift var i = 0; public func test_condition() { NSLog("start") self.condition = NSCondition() DispatchQueue.global(qos: .default).async { self.condition?.lock() while(self.i == 0) { self.condition?.wait() } NSLog("1:"+Thread.current.description); self.condition? .unlock() } DispatchQueue.global(qos: .default).async { self.condition?.lock() while(self.i == 0) { self.condition?.wait() } NSLog("2:"+Thread.current.description); self.condition? .unlock() } DispatchQueue.global(qos: Async {self.condition?.lock() sleep(3) self.i += 1 // Wake up the thread self.condition?.signal() // self.condition?.broadcast() NSLog("3:"+Thread.current.description); self.condition? .unlock() } NSLog("end") }Copy the code
use mutex and cond
In the Swift Foundation source nslock. Swift file, find the following code (extract some key code) :
private typealias _MutexPointer = UnsafeMutablePointer<pthread_mutex_t> private typealias _ConditionVariablePointer = UnsafeMutablePointer<pthread_cond_t> open class NSCondition: NSObject, NSLocking { internal var mutex = _MutexPointer.allocate(capacity: 1) internal var cond = _ConditionVariablePointer.allocate(capacity: Pthread_mutex_init (mutex, nil) pthread_cond_init(cond, nil) Nil)} open func lock() {pthread_mutex_lock(mutex)} open func unlock() {// Use mutex to unlock Pthread_mutex_unlock (mutex)} open func wait() {pthread_cond_wait(mutex)} open func wait(until limit: Date) -> Bool { guard var timeout = timeSpecFrom(date: Limit) else {return false} return pthread_cond_timedWait (cond, mutex, &timeout) == 0} Pthread_cond_signal (cond)} open func broadcast() {// Broadcast conditional signal, broadcast all threads pthread_cond_broadcast(cond)}}Copy the code
NSConditionLock
NSConditionLock is a conditional lock provided by the Foundation framework that ensures that threads can only acquire the lock if certain conditions are met. NSConditionLock encapsulates the NSCondition variable with a cond condition of type Int. Compared with NSCondition, the degree of freedom is higher. Let’s start with common apis:
Func unlock() // unlock func unlock() // unlock func unlock() Open func 'try' () -> Bool open func tryLock(whenCondition condition: Int) -> Bool open func unlock(withCondition condition: Open func lock(before limit: Date) -> Bool // Attempts to acquire the lock before the specified time. This method blocks thread execution until the lock can be acquired or the limit is reached. open func lock(whenCondition condition: Int, before limit: Date) -> BoolCopy the code
It’s easy to use.
//swift
public func test_conditionlock(a) {
NSLog("start")
// Initialize the lock with cond = 3
self.conditionLock = NSConditionLock(condition: 3)
DispatchQueue.global(qos: .default).async {
// Get lock and wait for cond == 1
self.conditionLock?.lock(whenCondition: 1)
NSLog("1:"+Thread.current.description);
self.conditionLock?.unlock(withCondition: 2)}DispatchQueue.global(qos: .default).async {
// Get the lock, wait cond == 4, wait up to 10 seconds
self.conditionLock?.lock(whenCondition: 4, before: Date().advanced(by: 15))
NSLog("2:"+Thread.current.description);
self.conditionLock?.unlock(withCondition: 2)}DispatchQueue.global(qos: .default).async {
// Get lock and wait for cond == 3
self.conditionLock?.lock(whenCondition:3)
sleep(5)
NSLog("3:"+Thread.current.description);
self.conditionLock?.unlock(withCondition: 1)}NSLog("end")}Copy the code
use NSCondition
NSConditionLock: conditionlock: conditionlock: conditionlock: conditionlock: conditionlock: conditionlock: conditionlock: conditionlock
open class NSConditionLock : NSObject.NSLocking {
internal var _cond = NSCondition(a)internal var _value: Int
internal var _thread: _swift_CFThreadRef?
public init(condition: Int) {
// Initialize the condition variable
_value = condition
}
open func lock(a) {
/ / lock
let _ = lock(before: Date.distantFuture)
}
open func unlock(a) {
/ / unlock
_cond.lock()
_thread = nil
_cond.broadcast()
_cond.unlock()
}
open func lock(whenCondition condition: Int) {
let _ = lock(whenCondition: condition, before: Date.distantFuture)
}
open func `try`(a) -> Bool {
return lock(before: Date.distantPast)
}
open func tryLock(whenCondition condition: Int) -> Bool {
return lock(whenCondition: condition, before: Date.distantPast)
}
open func unlock(withCondition condition: Int) {
// Unlock and set the condition variable
_cond.lock()
_thread = nil
_value = condition
_cond.broadcast()
_cond.unlock()
}
open func lock(before limit: Date) -> Bool {
_cond.signal()
_cond.lock()
while _thread ! = nil {
if !_cond.wait(until: limit) {
_cond.unlock()
return false
}
}
_thread = pthread_self()
_cond.unlock()
return true
}
open func lock(whenCondition condition: Int.before limit: Date) -> Bool {
// Lock, not the first time or condition variable does not match, wait for _cond.signal()
_cond.lock()
while _thread ! = nil || _value ! = condition {
if !_cond.wait(until: limit) {
_cond.unlock()
return false
}
}
_thread = pthread_self()
_cond.unlock()
return true}}Copy the code
NSRecursiveLock
NSRecursiveLock is a recursive lock provided by the Foundation framework. The effect is that a lock can be acquired multiple times by the same thread without causing a deadlock. Like synchronized(objc_sync), the underlying encapsulation of pthread_mutex is recursive. Let’s look at the API first:
Open func 'try' () -> Bool // Keep trying to lock in the specified time, Open func lock(before LIMIT: Date) -> BoolCopy the code
It’s also easy to use:
//swift
public func test_recursivelock(a) {
NSLog("start")
self.recursiveLock = NSRecursiveLock(a)DispatchQueue.global(qos: .default).async {
self.recursiveLock?.lock()
sleep(3)
// Get the lock again
self.recursiveLock?.lock()
NSLog("1:"+Thread.current.description);
self.recursiveLock?.unlock()
self.recursiveLock?.unlock()
}
DispatchQueue.global(qos: .default).async {
self.recursiveLock?.lock()
sleep(3)
NSLog("2:"+Thread.current.description);
self.recursiveLock?.unlock()
}
NSLog("end")}Copy the code
use recursive mutex
Next, let’s look at the underlying implementation of NSRecursiveLock. In the Swift Foundation source nsLock. Swift file, find the following code (extracted some key code) :
//swift
private typealias _MutexPointer = UnsafeMutablePointer<pthread_mutex_t>
private typealias _RecursiveMutexPointer = UnsafeMutablePointer<pthread_mutex_t>
private typealias _ConditionVariablePointer = UnsafeMutablePointer<pthread_cond_t>
open class NSRecursiveLock: NSObject.NSLocking {
// Initialize the pthread_mutex_t lock
internal var mutex = _RecursiveMutexPointer.allocate(capacity: 1)
private var timeoutCond = _ConditionVariablePointer.allocate(capacity: 1)
private var timeoutMutex = _MutexPointer.allocate(capacity: 1)
public override init(a) {
super.init(a)// Initialize the pthread_mutexattr_t mutex attribute and set the recursive type PTHREAD_MUTEX_RECURSIVE
var attrib = pthread_mutexattr_t()
withUnsafeMutablePointer(to: &attrib) { attrs in
pthread_mutexattr_init(attrs)
pthread_mutexattr_settype(attrs, Int32(PTHREAD_MUTEX_RECURSIVE))
pthread_mutex_init(mutex, attrs)
}
pthread_cond_init(timeoutCond, nil)
pthread_mutex_init(timeoutMutex, nil)}open func lock(a) {
// Use mutex to lock
pthread_mutex_lock(mutex)
}
open func unlock(a) {
// Unlock with mutex
pthread_mutex_unlock(mutex)=
// Wakeup any threads waiting in lock(before:)
pthread_mutex_lock(timeoutMutex)
pthread_cond_broadcast(timeoutCond)
pthread_mutex_unlock(timeoutMutex)
}
open func `try`(a) -> Bool {
return pthread_mutex_trylock(mutex) = = 0
}
open func lock(before limit: Date) -> Bool {
if pthread_mutex_trylock(mutex) = = 0 {
return true
}
return timedLock(mutex: mutex, endTime: limit, using: timeoutCond, with: timeoutMutex)
guard var endTime = timeSpecFrom(date: limit) else {
return false
}
return pthread_mutex_timedlock(mutex, &endTime) = = 0}}Copy the code
The Next
- Common locks in iOS
- iOS OSSpinLock
- Underlying analysis of iOS Synchronized
- IOS NSLock underlying analysis
- IOS Atomic low-level analysis
Refer to the link
swift foundation opensource objc4