This is the 24th day of my participation in the August More Text Challenge

IOS development, various locks you know how much? NSLock, NSCondtion, NSRecursiveLock, NSCondition…….

review

In the previousA blogIn, introduces the types of locks inIn the previousThe blog has been right@synchronizedLock source code analysis, there are some other locks are not introduced, so this blog will analyze some of the other locks!

Multithreading in iOS (I) – Processes and threads

IOS low-level exploration of multithreading (II) – Threads and locks

IOS low-level exploration of multithreading (3) – GCD

IOS low-level exploration of multithreading (4) – GCD queue

IOS bottom exploration of multithreading (five) – GCD different queue source analysis

IOS bottom exploration of multithreading (six) – GCD source analysis (sync function, async asynchronous function)

IOS low-level exploration of multithreading (seven) – GCD source analysis (cause of deadlock)

IOS bottom exploration of multithreading (eight) – GCD source analysis (function synchronization, asynchrony, singleton)

IOS bottom exploration of multithreading (nine) – GCD source analysis (fence function)

IOS low-level exploration of multithreading (10) – GCD source analysis (semaphore)

IOS bottom exploration of multithreading (11) – GCD source analysis (scheduling group)

IOS Low-level exploration of multithreading (12) – GCD source code analysis (event source)

Multithreading of iOS low-level exploration (13) – How much do you know about the types of locks?

Multithreading in iOS (14) — What do you know about @synchronized locks?

IOS bottom exploration of multithreading (15) – @synchronized source code analysis

1. Introduction to locks

1.1 Classification of locks

  • spinlocks: The thread repeatedly checks whether the lock variable is available. Since the thread keeps executing during this process, it is a kind ofBusy waiting. Once you get itspinlocks, the thread holds the lock until it explicitly releases the spin lock.spinlocksThe scheduling overhead of the process context is avoided and is therefore effective for situations where threads block only for short periods of time.
  • The mutex: is used in multithreaded programming to prevent two threads working on the same common resource (such as a global variable) at the same timeRead and writeThe mechanism. This is accomplished by slicing code into critical sections one by oneThe mutexThe role of.

Mutexes include NSLock, pthread_mutex, and @synchronized

1.2 Classification of locks

  • Conditions for the lock: is a condition variable that is locked when a process’s resource requirements are not met. When the resource is allocated, the conditional lock is opened and the process continues, as in:NSCondition ,NSConditionLock
  • Recursive lockingThe same thread can be locked N times without causing a deadlock.NSRecursiveLock,pthread_mutex(recursive)
  • SemaphoreMutex is a more advanced synchronization mechanismsemaphoreThe only value0/1Is a special case of. Semaphores can have more value space to implement more complexsynchronousNot just between threadsThe mutex, such as:dispatch_semaphore

Lock classification in fact, the basic lock includes three categories: spin lock mutex lock read and write lock, other such as conditional lock, recursive lock, semaphore is the upper packaging and implementation!

  • Read-write lock: Read/write lock is a special mutex lock. It divides visitors to a shared resource into readers and writers. Readers only read the shared resource, while writers write the shared resource.

2. NSLock

  1. For example 1

There is the following code:

- (void)is_crash{
    NSLog(@"reno");
    for (int i = 0; i < 10000; i++) {
        dispatch_async(dispatch_get_global_queue(0.0), ^{
            _testArray = [NSMutableArrayarray]; }); }}Copy the code
  • Run when unlocked

No lock, multithreaded access, crash, so now to lock and see what happens?

  • lock

Lock the case, will not crash, ensure the safety of the thread.

  1. For example 2
NSLog(@"jpreno");
dispatch_async(dispatch_get_global_queue(0.0), ^ {static void (^testMethod)(int);
			testMethod = ^(int value){

					if (value > 0) {
						NSLog(@"current value = %d",value);
						testMethod(value - 1); }}; testMethod(10);
		});
Copy the code
  • Print the result

There’s nothing wrong with printing the result, so add aforCycle?

Now, the printed data is messed up, which means multi-threaded access, so the solution islockSo where do I add it? Most people would add it here, as follows:So if you add it to the figure above, will it print normally? We don’t know yet, so let’s run the code and see!From running the print, the data is still out of order, obviouslyNSLockThe lock position of ✅ is not in the right place. Where is the lock position of ✅? Please see 👇 :The only way to solve the problem is to add the lock to the position shown in the picture, or simply add the lock to thetestMethod(10)This place is ok, too.

[jp_lock lock];/ / lock
testMethod(10);
[jp_lock unlock];/ / unlock
Copy the code

General locking, we like to write together with business code, as follows:It keeps recursing, it keeps locking, it doesn’t unlock, it deadlocks, it just hasn’t crashed yet, so why? NSLock does not support recursive locking, there is no recursion.

3. NSRecursiveLock

We remember there was a lockNSRecursiveLock, the lock performance is also good, and support recursion, use as follows:

NSRecursiveLock is recursive, but does not support multithreaded recursion, and crashes after only one run. Synchronized is a recursive and multithreaded lock.

By adding@synchronizedThis lock, it solves the problem perfectly,NSRecursiveLockIs solvedNSLock The notThe recursive nature, used here@synchronizedIs solvedNSRecursiveLockDo notMultithreaded sex.

4. NSCondition

The NSCondition object actually acts as a lock and a thread inspector.

  • The main purpose of locking is to protect data sources when detecting conditions and perform tasks triggered by conditions;
  • The thread checker mainly decides whether to continue running a thread based on conditions, that is, whether the thread is blocked.

1: [condition lock] : allows multiple threads to access and modify the same data source at the same time. Ensure that the data source is accessed and modified only once at the same time. Commands of other threads must wait outside the lock until the unlock is accessed. 3: [condition wait]: the current thread is in the waiting state. 4: [condition signal]: the CPU sends a signal to tell the thread to stop waiting and to continue.

Now take an example of producers and consumers, with the following code:

- (void)viewDidLoad {
    [super viewDidLoad];

    self.ticketCount = 0;
     _testCondition = [[NSCondition alloc] init];
    [self jp_testConditon];

}

#pragma mark -- NSCondition

- (void)jp_testConditon{
    
    // Create production-consumer
    for (int i = 0; i < 50; i++) {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0) ^ {[self jp_producer];
        });
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0) ^ {[self jp_consumer];
        });
        
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0) ^ {[self jp_consumer];
        });
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0) ^ {[selfjp_producer]; }); }} - (void)jp_producer{
    self.ticketCount = self.ticketCount + 1;
    NSLog(@" Produce an existing count %zd".self.ticketCount);
}

- (void)jp_consumer{
 
    if (self.ticketCount == 0) {
        NSLog(@" wait for count %zd".self.ticketCount);
    }
    self.ticketCount -= 1;
    NSLog("Consume one remaining count %zd".self.ticketCount);
}
Copy the code

The result is as follows:From the result of the run, you can see that there is a negative situation, you have consumed all the things that my producer produced, it is no longer there, you are still consuming, and there is an accident of unsafe access for the thread.

So we have to ensure the safety of production, consumption line data will need to lock processing, to ensure the safety in a multi-threaded, but this is just the guarantee of their internal, but consumer relationship between them, such as inventory, production may not notice, waiting for consumers, production ok to inform consumers to consumption.

Now for the lock transformation, as follows:

 (void)jp_producer{
    [_testCondition lock]; // Multithreading effects of operations
    self.ticketCount = self.ticketCount + 1;
    NSLog(@" Produce an existing count %zd".self.ticketCount);
    [_testCondition signal]; // Send a signal to inform the consumer, I have produced here, you can come to consume
    [_testCondition unlock];
}

- (void)jp_consumer{
 
     [_testCondition lock];  // Multithreading effects of operations
    if (self.ticketCount == 0) {
        NSLog(@" wait for count %zd".self.ticketCount);
        [_testCondition wait];// Wait for the producer to produce something
    }
    // Pay attention to the consumption behavior after waiting for the judgment of the condition
    self.ticketCount -= 1;
    NSLog("Consume one remaining count %zd".self.ticketCount);
     [_testCondition unlock];
}
Copy the code

Now, what happens when you lock it, is it safe? As follows:

Obviously, the print after locking is normal, no negative numbers appear, the data is safe!

  • If the product is not enough[_testCondition wait]Wait to make consumers stop spending
  • with[_testCondition signal]The simulation now has production and is ready to consume, signaling the waiting thread to consume

4. To summarize

  • Multithreaded access, the need to ensure the security of data, can continue to lock processing
  • NSLockRecursive locking is not supported
  • NSRecursiveLockThere is recursion, but no multithreading
  • NSConditionThe object actually acts as a lock and a thread inspector

More content continues to be updated

🌹 if you like, give it a thumbs up 👍🌹

🌹 feel harvest, can come to a wave, collection + attention, comment + forward, so as not to find me next time 😁🌹

🌹 welcome everyone to leave a message exchange, criticism and correction, learn from each other 😁, improve themselves 🌹