1. OSSpinLock High-level lock
OSSpinLock is called a spinlock, and threads waiting for locks are busy-wait, occupying CPU resources all the time.
At present, it is no longer safe, and there may be priority inversion problem.
If the thread waiting for the lock has a higher priority, it will always occupy CPU resources, and the thread with lower priority will not be able to release the lock.
Need to import header file #import <libkern/OSAtomic.h>
#import <libkern/OSAtomic.h> @interface OSSpinLockDemo() @property (assign, nonatomic) OSSpinLock lock; @end @implementation OSSpinLockDemo - (void)viewDidLoad { [super viewDidLoad]; // Initialization lock self.lock = OS_SPINLOCK_INIT; //Lock up OSSpinLockLock(&_lock); //Attempt to lock, return true unless you need to wait, and false unlock if you need to wait //bool result = OSSpinLockTry(&_lock); [self testSpinLock]; //Unlock OSSpinLockUnlock(&_lock); }
2. os_unfair_lock Low-level lock
os_unfair_lock is used to replace the unsafe OSSpinLock, which has been supported since iOS 10.
From the bottom invocation point of view, threads waiting for os_unfair_lock lock lock will be dormant, not busy, etc.
Need to import header file #import <os/lock.h>
#import <os/lock.h> @interface OSUnfairLockDemo() @property (assign, nonatomic) os_unfair_lock lock; @end @implementation OSUnfairLockDemo - (void)viewDidLoad { [super viewDidLoad]; // Initialization lock self.lock = OS_UNFAIR_LOCK_INIT; //Lock up os_unfair_lock_lock(&_lock); //Attempt to lock, return true unless you need to wait, and false unlock if you need to wait //bool result = os_unfair_lock_trylock(&_lock); [self testUnfairLock]; //Unlock os_unfair_lock_unlock(&_lock); }
ibireme< OSSpinLock is no longer secure > This article indicates that OSSpinLock is no longer secure. In the new version of iOS, the system maintains five different thread priorities / QoS: background, utility, default, user-initiated, user-interactive. High priority threads always execute before low priority threads, and a thread will not be disturbed by lower priority threads. This thread scheduling algorithm can cause potential priority inversion problems, thus destroying spinlock.
3. pthread_mutex - Need to be destroyed
#import <pthread.h> /* /* * Mutex type attributes */ #define PTHREAD_MUTEX_NORMAL 0 #define PTHREAD_MUTEX_ERRORCHECK 1 #define PTHREAD_MUTEX_RECURSIVE 2 #define PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_NORMAL */ @interface MutexDemo() @property (assign, nonatomic) pthread_mutex_t mutex; @end @implementation MutexDemo - (void)viewDidLoad { [super viewDidLoad]; // initiate static //pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // Initialization properties pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_DEFAULT); // Initialization lock pthread_mutex_init(_mutex, &attr); //pthread_mutex_init(_mutex, NULL); // air transfer is also the default PTHREAD_MUTEX_DEFAULT // Destruction attributes pthread_mutexattr_destroy(&attr); pthread_mutex_lock(&_mutex); [self testMutex]; pthread_mutex_unlock(&_mutex); } - (void)testMutex { NSLog(@"%s", __func__); } - (void)dealloc { pthread_mutex_destroy(&_mutex); }
#import <pthread.h> @interface MutexDemo() @property (assign, nonatomic) pthread_mutex_t mutex; @end @implementation MutexDemo - (void)viewDidLoad { [super viewDidLoad]; // Initialization properties pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); // Recursive Locks: Allows the same thread to repeatedly lock a lock pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); // Initialization lock pthread_mutex_init(_mutex, &attr); // Destruction attributes pthread_mutexattr_destroy(&attr); [self otherTest]; } - (void)testMutex { NSLog(@"%s", __func__); } - (void)otherTest { pthread_mutex_lock(&_mutex); NSLog(@"%s", __func__); static int count = 0; if (count < 10) { count++; [self otherTest]; } pthread_mutex_unlock(&_mutex); } - (void)dealloc { pthread_mutex_destroy(&_mutex); }
#import <pthread.h> @interface MutexDemo() @property (assign, nonatomic) pthread_mutex_t mutex; @property (assign, nonatomic) pthread_cond_t cond; @property (strong, nonatomic) NSMutableArray *data; @end @implementation MutexDemo - (void)viewDidLoad { [super viewDidLoad]; // Initialization properties pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);//Conditional lock // Initialization lock pthread_mutex_init(&_mutex, &attr); // Destruction attributes pthread_mutexattr_destroy(&attr); // Initialization conditions pthread_cond_init(&_cond, NULL); self.data = [NSMutableArray array]; [self otherTest]; } - (void)otherTest { [[[NSThread alloc] initWithTarget:self selector:@selector(__remove) object:nil] start]; [[[NSThread alloc] initWithTarget:self selector:@selector(__add) object:nil] start]; } // Producer-consumer model // Thread 1 // Delete elements from an array - (void)__remove { pthread_mutex_lock(&_mutex); NSLog(@"__remove - begin"); if (self.data.count == 0) { // wait for pthread_cond_wait(&_cond, &_mutex); } [self.data removeLastObject]; NSLog(@"Deleted element"); pthread_mutex_unlock(&_mutex); } // Thread 2 // Adding elements to an array - (void)__add { pthread_mutex_lock(&_mutex); sleep(1); [self.data addObject:@"Test"]; NSLog(@"Adding elements"); // signal pthread_cond_signal(&_cond); // Radio broadcast // pthread_cond_broadcast(&_cond); pthread_mutex_unlock(&_mutex); } - (void)dealloc { pthread_mutex_destroy(&_mutex); pthread_cond_destroy(&_cond); }
4,NSLock
NSLock is the encapsulation of mutex lock
5,NSRecursiveLock
NSRecursiveLock is also an encapsulation of mutex recursive locks. The API is basically the same as NSLock.
6,NSCondition
NSCondition is the encapsulation of mutex and cond
@interface NSConditionDemo() @property (strong, nonatomic) NSCondition *condition; @property (strong, nonatomic) NSMutableArray *data; @end @implementation NSConditionDemo - (void)viewDidLoad { [super viewDidLoad]; self.condition = [[NSCondition alloc] init]; self.data = [NSMutableArray array]; [self otherTest]; } - (void)otherTest { [[[NSThread alloc] initWithTarget:self selector:@selector(__remove) object:nil] start]; [[[NSThread alloc] initWithTarget:self selector:@selector(__add) object:nil] start]; } // Thread 1 // Delete elements from an array - (void)__remove { [self.condition lock]; NSLog(@"__remove - begin"); if (self.data.count == 0) { // wait for [self.condition wait]; } [self.data removeLastObject]; NSLog(@"Deleted element"); [self.condition unlock]; } // Thread 2 // Adding elements to an array - (void)__add { [self.condition lock]; sleep(1); [self.data addObject:@"Test"]; NSLog(@"Adding elements"); // signal [self.condition signal]; sleep(2); [self.condition unlock]; }
7,NSConditionLock
NSConditionLock is a further encapsulation of NSConditionLock, which can set specific condition values by default of 0.
@interface NSConditionLockDemo() @property (strong, nonatomic) NSConditionLock *conditionLock; @end @implementation NSConditionLockDemo - (void)viewDidLoad { [super viewDidLoad]; self.conditionLock = [[NSConditionLock alloc] initWithCondition:1]; [self otherTest]; } - (void)otherTest { [[[NSThread alloc] initWithTarget:self selector:@selector(__one) object:nil] start]; [[[NSThread alloc] initWithTarget:self selector:@selector(__two) object:nil] start]; [[[NSThread alloc] initWithTarget:self selector:@selector(__three) object:nil] start]; } - (void)__one { [self.conditionLock lock];//Lock directly regardless of condition value NSLog(@"__one"); sleep(1); [self.conditionLock unlockWithCondition:2]; } - (void)__two { [self.conditionLock lockWhenCondition:2];//The conditions must be met to lock NSLog(@"__two"); sleep(1); [self.conditionLock unlockWithCondition:3]; } - (void)__three { [self.conditionLock lockWhenCondition:3]; NSLog(@"__three"); [self.conditionLock unlock]; }
8,dispatch_semaphore
Semaphore is called semaphore
The initial value of the semaphore can be used to control the maximum number of concurrent access by threads
The initial value of semaphore is 1, which means that only one thread is allowed to access resources at the same time to ensure thread synchronization.
@interface SemaphoreDemo() @property (strong, nonatomic) dispatch_semaphore_t semaphore; @end @implementation SemaphoreDemo - (void)viewDidLoad { [super viewDidLoad]; self.semaphore = dispatch_semaphore_create(5);//Setting to 1 is a serial queue and > 1 is concurrent } - (void)otherTest { for (int i = 0; i < 20; i++) { [[[NSThread alloc] initWithTarget:self selector:@selector(test) object:nil] start]; } } - (void)test { // If the semaphore value > 0, subtract the semaphore value by 1, and then continue executing the code // If the value of the semaphore <= 0, it will sleep and wait until the value of the semaphore becomes > 0, let the value of the semaphore be reduced by 1, and then continue to execute the code. dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER); sleep(2); NSLog(@"test - %@", [NSThread currentThread]); // Let the semaphore value + 1 dispatch_semaphore_signal(self.semaphore); }
9. synchronized (recursive lock)
@ synchronized is a kind of encapsulation of mutex recursive lock, which is not prompted when xcode is written, and its performance is relatively low.
@ synchronized(obj) generates a recursive lock corresponding to obj, and then performs locking and unlocking operations
/* typedef struct alignas(CacheLineSize) SyncData { struct SyncData* nextData; DisguisedPtr<objc_object> object; int32_t threadCount; // number of THREADS using this block recursive_mutex_t mutex; } SyncData; */ //The underlying implementation, objc_sync.mm, objc_sync_enter objc_sync_exit syncData, contains a hash table lookup c++ structure @synchronized([self class]) { [self otherTest]; }
Performance ranks from high to low: os_unfair_lock > OSSpinLock > dispatch_semaphore > pthread_mutex > NSLock > NSCondition > pthread_mutex (recursive) > NSConditionLock >@synchronized (time difference calculated on lock and unlock codes) OSSpinLock,dispatch_semaphore performs much better than other locks, but OSSpinLock is superior to OS Lock. Because of the problem of priority inversion, Apple introduced os_unfair_lock as an alternative to iOS 10, and its performance did not decrease that year, but it could not be used after iOS 10 (although spin lock performance is better than mutex lock). It can be seen that @synchronize and NSConditionLock are obviously the worst performers, if the project is particularly sensitive to performance, build It is suggested that dispatch_semaphore be used, and @synchronize can be used if it is convenient, with little impact.