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

The classification of the lock

We usually divide locks into two categories: spin locks and mutex locks.

  • Exclusive locks:
    • Mutex, yesThe mutexandsynchronousTwo features; During the execution of our program, there will be multiple threads processing related tasks, which may be simultaneously processing tasks. Therefore, mutually exclusive means that when thread A is performing tasks, thread B cannot perform operations (idle). And it needs to be done sequentially;
    • Mutexes are also divided intoRecursive lockingandNon-recursive locks;
  • The spin lock.
    • The same two threads are executing related tasks. While thread A is processing tasks, thread B is waiting. Equivalent to theThe mutexOn the basis ofBusy etc.; (Spin locks are also a special kind of mutex.)
  • Third type (read-write lock)

NSLock and NSRelock analysis

NSLock

Let’s examine a piece of code:

It is obvious that this code is not thread safe, so run the following:

To resolve crashes, we can use NSLock:

Let’s look at another code demo:

We can see that the input is fine, but what if we add a for loop around it?

We see that the printing results of data have been messed up because of thread insecurity caused by multithreading;

Next, we use NSLock to lock the calculation process:

Unlock (testMethod); unlock (testMethod);

In the process of using NSLock, you need to prevent recursively locking. Because NSLock is a non-recursive lock;

Like this:

Will result in a recursive locking situation;

So, since NSLock is a non-recursive lock, it is used to avoid the occurrence of recursive lock, so we can directly use recursive lock can avoid this situation? Let’s try it with @synchronized:

NSRecursiveLock

So, can we use NSRecursiveLock to solve this problem?

Let’s modify the code as follows:

As a result, the program crashed after printing it once; This is because our program is multithreaded, and NSRecursiveLock is not a multithreaded recursive lock; When we use, we should pay attention to the problem of multithreading:

NSRecursiveLock solves the recursibility of locks, but not multithreading, so in this case we recommend @synchronized with multithreading recursibility:

NSCondition analysis

The object of NSCondition actually acts as a lock and a thread inspector: the lock is mainly used to protect the data source when detecting the condition and perform the task triggered by the condition; Thread checker is mainly based on conditions to decide whether to continue to run the thread, that is, whether the thread is blocked;

Related API usage:

  • [condition lock]: Allows multiple threads to access and modify the same data source at the same time. This ensures that the data source can be accessed and modified only once at the same timelockWait untilunlockTo continue the visit;
  • [condition unlock]And:lockPair use;
  • [condition wait]: Makes the current thread wait.
  • [condition signal]:CPUSignal the thread to stop waiting and continue executing;

Let’s simulate a production and sales model with the following code:

We run it and see the result:

We found that inventory was actually negative; And when count = 0, we wait, and at the next moment we have consumption;

When the producer’s inventory is 0, the consumption process should be in a waiting state, and when the inventory is available, the consumer should be notified not to wait any longer:

  • [_testCondition lock]and[_testCondition unlock]To ensure the production and consumption of two lines of data security;
  • [_testCondition wait]When the task reaches a certain condition (production inventory is0), suspend the consumption task and wait;
  • [_testCondition signal]When the production has inventory, signal to the consumer, the consumer cancelswaitWait state, start to consume;

Foundation source lock encapsulation

NSLock

By analyzing NSLock, we can find that lock and UNLOCK methods come from THE NSLocking protocol of NSLock, so many custom locks have lock and UNLOCK methods, just because the NSLocking protocol is implemented.

NSLock is derived from the Foundation framework, but we know that the OC version of the Foundation framework is not open source, so how do we investigate? Here we can use the Swift version of Foundation source code for analysis;

Let’s look at the NSLock implementation code:

We found that in iOS, NSLock is implemented by pthread_mutex_t.

Let’s look at the implementation of lock and unlock methods:

NSLock lock and UNLOCK are implemented by pthread_mutex_lock(mutex) and pthread_mutex_unlock(mutex).

NSRecursiveLock

Next, let’s examine the implementation of NSRecursiveLock:

NSRecursiveLock implements THE NSLocking protocol. What about its lock and unlock methods?

NSRecursiveLock encapsulates pthread_mutex_t, but NSLokc is a non-recursive lock.

Comparing the init method for both locks, We found that one is recursive and one is non-recursive because the init implementation of NSRecursiveLock set pthread_mutexattr_setType (attrs, Int32(PTHREAD_MUTEX_RECURSIVE))

NSCondition

NSCondition is still implemented via pthread_mutex_t:

Lock and unlock methods:

Condition_conditionvariablepointer (); / / condition_conditionvariablePointer (); / / condition_conditionvariablePointer (); / / condition_conditionvariablePointer ();

And encapsulation of NSCondition’s wait method:

NSLock, NSRecursiveLock, and NSCondition all encapsulate pthread_mutex_t.