Multi thread lock in 8. iOS

Note: although some things may not be what you expected, but when it really happened, or very difficult to accept, or take a little time to ease the negative emotions, as soon as possible to stand up! Come on. Spent one and a half days, various materials, summed up the iOS thread lock on the knowledge, I hope I can learn from some, but also hope to help you have the same needs! (if there is any mistake in this article, please also propose and communicate with each other)


This article mainly introduces:

  • mutex
  • recursive mutex
  • Read-write lock
  • Spin lock
  • Distribution lock
  • Conditional variable
  • Semaphore
  • Fence
  • The performance of some commonly used locks.
1. mutex (Mutex)

Typically, when a thread attempts to obtain a lock occupied by another thread, it will hang up and let CPU out until the lock is released.

  • Mutex implementation: @synchronized: implementation of singleton mode NSLock: can not iterate lock, if two times lock, but not unlock, will produce a deadlock problem.

1.@synchronized synchronous lock

  • Routine: * / * * setproperty – * / (void) setMyTestString: (NSString *) myTestString{@synchronized (self) {/ / todo something _myTestString = myTestString;}}
  • The design used in single mode: routines: + (instancetype) shareInstance{/ / 1 defines a static instance of static TestSynchronized *myClass, the initial value of nil = nil; / / 2 add synchronization lock, create an instance of @synchronized (self) {/ / 3 to judge whether the instance created, created the exit lock, return directly to the instance of if (! MyClass) {/ / 4 is not created, creates a new instance of alloc] init] and return to myClass = [[self;}}} return myClass; at this time in order to ensure the singleton pattern is more rigorous, need to override the allocWithZone method, ensure that other developers can use alloc and init method, no longer create new objects. When necessary, you also need to override the copyWithZone method to prevent the copy attribute from affecting singleton patterns.

There is also a lighter way to implement singleton patterns in iOS, that is, using the dispatch_once function in GCD.

Routine:

(instancetype) shareInstance{static + TestSynchronized *myClass = nil; static dispatch_once_t once_token; dispatch_once (& once_token, myClass = [[self ^{alloc] init]; return myClass;}});

2.NSLock

  • Example: static (void) – NSLock *mylock; viewDidLoad viewDidLoad] {[super = [[NSLock; mylock alloc] init];} – (void) myLockTest1{if ([mylock tryLock] to do something [mylock) {/ / unlock];}} – (void) myLockTest2{[mylock lock] to do something [mylock; / / unlock];}
2. recursive locks (Recursive, Lock)
  • A recursive lock can be called repeatedly by the same thread without causing a deadlock, which means no deadlocks when multiple locks are made by the same thread. This is mainly used in loops or recursive operations.
  • You can allow multiple locks on the same thread without causing deadlocks.
  • A recursive lock tracks the number of times it is lock. Each successful lock must balance the call to the unlock operation. Only when all of this balance is reached can the lock be released for use by other threads.
  • NSRecursiveLock *myRecursiveLock = [[NSRecursiveLock alloc] routines: init]; dispatch_async (dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{static void (^MyRecursiveLockBlk) (int value); MyRecursiveLockBlk (int = value) ^ {[myRecursiveLock (lock]; if value > 0 do something NSLog) {/ / to (@ “MyRecursiveLockBlk value =%d, value) MyRecursiveLockBlk (value; 1);}}; [myRecursiveLock unlock]; MyRecursiveLockBlk (6);}); if the recursive routines lock into the mutex:
    NSRecursiveLock *myRecursiveLock = [[NSRecursiveLock alloc] init]; NSLock *myLock = [[NSLock replaced
    alloc], will be init]; The issue of life and death.
3. read write lock (Read-write Lock)
  • Read and write locks for visitors to read and write two, when read and write lock mode in reading, to read all the way to access the locked resources, will gain access to, and all attempts to write lock will be locked on the blocking thread, until all the read lock release.
  • When in the write lock mode, all threads attempting to lock it are blocked.
  • Example: #import “ViewController.h” #import < pthread.h> @interface (ViewController) @property (nonatomic, copy) NSString *rwStr @end @implementation ViewController pthread_rwlock_t; rwlock; – (void) viewDidLoad {[super viewDidLoad]; / / initialize the read and write lock pthread_rwlock_init (& rwlock, NULL); __block int i; dispatch_async (dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ^{), I = 5; while (i> =0) {NSString *temp = [NSString stringWithFormat:@ writing =%d, i]; [self writingLock:temp]; i–;}}); dispatch_async (dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{I = 5; while (i> =0) {[self readingLock]; i–; }});} / / write lock – (void) writingLock: (NSString *) temp{pthread_rwlock_wrlock (& rwlock); / / writing self.rwStr = temp; NSLog (@ “% @”, temp); pthread_rwlock_unlock (& rwlock);} / / read lock – (NSString * readingLock{pthread_rwlock_rdlock (&amp); rwlock); / / reading NSString *str = self.rwStr; NSLog (reading = = @% @ “, self.rwStr); pthread_rwlock_unlock (& rwlock); return str @end;}
4. spin lock (Spin Lock)
  • Spin locks are similar to mutex locks
  • But the difference is that the spin lock is non blocking, and when a thread cannot obtain a spin lock, it spins until the lock is released and the thread does not hang up during the wait. (essentially, if the spin lock has been held by another execution unit, the caller has been waiting for the spin lock to remain and the lock has been unlocked).
  • Spin lock users generally keep the lock very short and at this time their efficiency is much higher than mutex locks.
  • The duration of the spin lock hold is the advantage of preemptive failure: the efficiency is high and the thread switching is not necessary: if a thread occupies the lock for too long, the spin will consume CPU resources
  • Routine: / / header file #import < libkern/OSAtomic.h&gt static OSSpinLock; / / initialize spin lock myLock = OS_SPINLOCK_INIT; / / use the spin lock – (void) SpinLockTest{OSSpinLockLock (& myLock); / / to do something OSSpinLockUnlock (& myLock);}
5. distribution locks (Didtributed, Lock)
  • Distributed locking across processes is a tool for inter process synchronization, and the bottom layer is a mutex with a file system that does not force the process to sleep, but rather serves as a notification.
  • NSDistributedLock does not implement the NSLocking protocol, so there is no lock method that blocks threads, instead the nonblocking tryLock method gets the lock and the unlock method is used to release the lock.
  • If a lock – in process exits before releasing the lock, then the lock cannot be released until the lock is secured by breakLock.
6. conditional variable (Condition, Variable)
  • Usage: if a thread needs to wait for a condition to continue, and this condition is generated by another thread, the conditional variable is used at this time. The common situation is: producer consumer problem.
  • A conditional variable allows a thread to wait for a condition and will receive a notification when the condition is satisfied. Multithreading also competes with the conditional variable and waits for the condition to occur, so the conditional variables usually work with the mutex. NSCondition: is a combination of mutexes and condition of the lock, a thread is blocked waiting for signal, can be another thread to wake up, because of the difference of operating system, even without transmitting the signal message thread may also be awakened, so it is necessary to increase the predicate variable to ensure the correctness of the program. NSConditionLock: unlike the implementation mechanism of NSCondition, when the defined condition is established, the lock is obtained, and the lock is released. NSCondition routines: *condition = [[NSCondition NSCondition / / create lock alloc] init]; static int count = 0; / / producer dispatch_async (dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{while (count< 20) {[condition lock]; / / count + + production; NSLog (@ “production =%d”, count); [condition signal]; [condition unlock]};}); / / consumer dispatch_async (dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{while (count> 0) {[condition lock]; / / count – NSLog (@ consumption; consumption surplus =%d, count); [condition unlock];}}); / / create NSConditionLock routines: lock NSConditionLock *condLock = [[NSConditionLock alloc] initWithCondition:Condi TionHASNOT]; static int count = 0; / / producer while (true) {[condLock lock]; / / count + + [condLock production; unlockWithCondition:ConditionHAS];} / / consumer while (true) {[condLock lockWhenCondition:ConditionHAS]; / / count – [condLock unlockWithCondition: consumption; (count< =0? ConditionHASNOT: ConditionHAS]);}
7. semaphores (Semaphore)
  • Semaphores: can be a special mutex that can be a counter to the resource
  • You can use the Dispatch Semaphore implementation in GCD, where Dispatch Semaphore is a hold count signal, which is the count type signal in multithreaded programming. When the count is 0, wait for a count greater than or equal to 1, minus 1 is not wait.
8. barriers / barriers (Barrier)
  • The fence must be executed separately and cannot be executed concurrently with other tasks. The fence is only meaningful to the concurrent queue.
  • The fence only waits for the current queue, and all concurrent tasks are executed, then it is executed separately, with execution, and then continues down in the normal manner.

Performance comparison of thread locks in iOS:

Click here to refer to the web site

  • No1. spin lock OSSpinLock consumes the least amount of time
  • No2.pthread_mutex
  • No3.NSLock/NSCondition/NSRecursiveLock takes time to approach
  • No4.@synchronized
  • No5.NSConditionLock
  • The performance of the fence is not very good, and is rarely used in actual development. (the author encountered in a recent interview and asked what the performance of the fence is I didn’t know the performance of the fence in the actual application is not very satisfactory, and asked what the apple official locks are often used It should be a spin lock, but I didn’t know it at the time