This is a continuation of our blog on multithreaded synchronization (do you know about multithreaded spin locks, mutex locks, recursive locks, etc.)?
GNUstep introduction
Let’s take a look at one more thing before we move on to other locks. We know that under the Foundation framework, the only source code available from Apple is NSObject, and NSString, NSArray, NSRunLoop, NSThread, and so on are not available. Only a partial implementation of NSObject is given, if we really want to look at the source code. Through assembly, the break points can be seen step by step, but this is a bit of trouble, you need to know assembly language, and bit by bit debugging to know. So here’s another solution, called GNUstep.
GNUstep is one of the projects of the GNU Project. The GNU Project is a software project that wants to open source lots and lots of source code, and wants it to be free. We can think of this project as doing lots and lots of open source projects. One of the GNU projects is GNUstep, which is an open-source re-implementation of Cocoa’s OC libraries. While Apple’s NSString, NSArray, NSRunLoop, NSThread, etc., are not open sourced,GNUstep has reimplemented them and made them open sourced.
GNUstep source code download address (recommended to download Base1.26.0 version)
Although GNUstep is not the official source code of Apple, but it has a certain reference value, it is very close to the implementation of apple source code. See the screenshot below:
It has a certain reference value, for us to understand something later has a very important role.
Next, let’s look at conditional locking
Pthread_mutex (conditional lock)
We are familiar with mutex’s mutexes and recursive locks, so let’s go straight to conditional locks. First, let’s see what my requirements are, as shown below:
My business requirement is that if dataMuArr. Count ==0, I don’t delete it, I will delete it when dataMuArr has data. In this case, we can use conditional lock, see below:
As you can see from the log output, conditional locking does address this requirement. Pthread_cond_wait is unlocked when it sleeps, so the add method can continue to execute, and the lock is unlocked when it wakes up, so the lock and unlock still occur in pairs. Broadcast (&_cond); broadcast(&_cond); broadcast(&_cond);
NSLock, NSRecursiveLock, NSCondition
NSLock: this is a wrapper around the pthread_mutex lock. It looks like an OC object
– (BOOL)tryLock; // Try locking
– (BOOL)lockBeforeDate:(NSDate*)limit; // Before this time, if I can wait for the lock to unlock I will wait, otherwise NOT
– (void)lock; / / lock
– (void)unlock; / / unlock
The four main ones, let’s just use them, they’re all very clear:
The above results are clear, no problem, and very simple to use. One other thing to note here, we can use my last blog to look at the assembly call process, and you’ll see the following
Because there’s caching, there’s methods, there’s all the messaging, what’s the use of knowing that? This gives us a performance comparison to thread synchronization, which is certainly not as efficient as pthread_mutex because it executes a lot more code.
If we can also find the implementation of NSLock through the interrupt point, the specific call and so on, but find it is very troublesome, then we can use GNUstep to find the above mentioned, as shown in the following figure:
This is clearly a wrapper around the pthread_mutex lock.
NSRecursiveLock: NSRecursiveLock encapsulates the pthread_mutex recursive lock. NSRecursiveLock: NSRecursiveLock encapsulates the pthread_mutex recursive lock.
**NSCondition:** This is a conditional lock that encapsulates pthread_mutex and cont.
– (void)wait; / / wait for
– (BOOL)waitUntilDate:(NSDate*)limit; // Before this time, if I can wait for the lock to unlock I will wait, otherwise NOT
– (void)signal; / / signal
– (void)broadcast; / / radio
– (void)lock; / / lock
– (void)unlock; / / unlock
I’ll just show you how it works, you can use conditional locks, you can use normal locks. I’ll just show you the previous one:
NSConditionLock,
**NSConditionLock:** NSCondition conditionlock :** NSCondition conditionlock :** NSCondition conditionlock
At this point, if we set the initialization condition to something else, the program will remain dormant and will not print anything. With this lock, we can control the order of execution of multiple threads, no matter how many threads we have. This is also very clear, I won’t go into detail
dispatch_queue (DISPATCH_QUEUE_SERIAL)
It is also possible to achieve thread synchronization using serial queues directly from GCD. We can’t think of thread synchronization, but locks. We need to know what the nature of thread synchronization is, that is, multiple threads are preempting the same resource, so serial queues can also solve the problem of thread synchronization. Let’s take selling tickets, for example.
Dispatch_semaphore_t,
“Dispatch_semaphore_t” is called a semaphore.
The initial value of a semaphore that can be used to control the maximum number of concurrent accesses by a thread. If we set the maximum number to 1, then we can achieve thread synchronization. Now let’s look at how to use it
Dispatch_semaphore_wait (self.semaphore, DISPATCH_TIME_FOREVER): if semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER): if semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER): Until the value of the semaphore is 0, then it will sleep and wait. If it is now then it will be executed immediately. If it is now then it will be executed immediately. If it is now then it will be executed immediately.
Dispatch_semaphore_signal (self.semaphore): dispatch_semaphore_signal(self.semaphore): dispatch_semaphore_signal(self.semaphore)
So in our previous code, all we had to do was set the semaphore value to 1 to do thread synchronization, so you can try that yourself.
@ synchronized,
I believe many have seen this keyword
Synchronized is a pthread_mutex recursive lock encapsulation, we refer to GNUstep to reference the source code.
It is the easiest to write, so here’s how to use it:
It is very simple to write, but also can solve the thread synchronization. Synchronized (self) self is the key and the lock value is the dictionary (GNUstep). So if it’s the same lock,@synchronized (self) where the self object must be the same object.
With that said, these are all common solutions. And there are other solutions.
Summary of thread synchronization:
1. Performance optimization comparison of synchronization schemes:
Here is a sorting order from high to low, but also measured, for your reference:
Os_unfair_lock (supported only after iOS10)
OSSpinLock (not recommended, deprecated after iOS10)
dispatch_semaphore_t
pthread_mutex
dispatch_queue (DISPATCH_QUEUE_SERIAL)
NSLock
NSCondition
pthread_mutex (recursive)
NSRecursiveLock
NSConditionLock
@synchronized
Therefore, dispatch_semaphore_t and ****pthread_mutex are recommended. If you have a lot of initialization code, you can define macros.
2. Comparison of spin locks and mutex
(Although the spin lock is no longer used, because only one is still obsolete, but sometimes interview questions, so we will mention here)
When is it cost-effective to use spinlocks?
The expected wait time of the thread is short; Locking code (critical sections) is often invoked, but contention rarely occurs; CPU resources are not tight. Multicore processor
When is it cost-effective to use a mutex?
The expected thread wait time is long. Single-core processor; The critical area is operated by IO; Critical section code complex or large loop.
Then I will continue to work hard to write other blogs, your support is my biggest motivation!