This is the 9th day of my participation in the August More Text Challenge
1. Introduction to locks
1.1 Lock performance
When multithreading is used in development, there are thread-safety issues, such as data handling in asynchronous functions on concurrent queuesRead and write operations
, will be generated without lockingdata race
Data competition. Our previous source code exploration also found on the data read and write add and delete add lock operation. We test it in real projectsdata race
The case can be selected in SettingsThread Sanitizer
Conduct tests.
Locks are more commonly used, for example@synchroized
.NSLock
.dispatch_semaphore
And so on, the figure below is a lock performance diagram of YY GodAnd you can see that@synchorized
The most time, we use code to simulate each lock time, run under the simulatoriPhone12
Version 14.5
Running iPhone11 version 14.5 on a real phone significantly reduced the time taken by @synchorized, indicating that apple has optimized it on a real phone.
1.2 Classification of locks
-
Spin lock: The thread repeatedly checks that the lock variable is available. Because the thread keeps executing during this process, it is a busy wait. Once a spinlock is acquired, the thread holds it until it explicitly releases the spinlock. Spin-locks avoid the scheduling overhead of the process context and are therefore effective in situations where threads block only for short periods of time. Common spin locks are
- atomoc
- OSSpinLock
-
Mutex: A mechanism used in multithreaded programming to prevent two threads from simultaneously reading or writing to the same common resource, such as a global variable. This is accomplished by slicing code into critical sections one by one. The mutexes are:
- NSLock
- pthread_mutex
- @synchronized
-
Conditional locks: Conditional variables that sleep when certain resource requirements of a process are not met, i.e. locked. When the resource is allocated, the conditional lock is opened and the process continues
- NSConditionLock
- NSCondition
-
Recursive locking: the same thread locks N times without causing a deadlock
- NSRecursiveLock
- pthread_mutex(recursive)
-
Semphore: a more advanced synchronization mechanism. Mutex is a special case of semaphore with a value of 0/1. Semaphores can have more value space for more complex synchronization, rather than just mutual exclusion between threads.
- dispatch_semaphore
-
Read/write lock: Read/write lock is a special kind of spin lock. It divides visitors to a shared resource into readers and writers. Readers only read the shared resource, while writers write the shared resource. This type of lock improves concurrency over a spin lock because in a multiprocessor system it allows multiple readers to access a shared resource at the same time, with the maximum possible number of readers being the actual number of logical cpus. Writers are exclusive; a read/write lock can have only one writer or more readers at a time (depending on the number of cpus), but not both readers and writers. Preemption also fails during read/write lock holding.
In fact, the basic lock includes three types of spin lock mutex read and write lock, other such as conditional lock, recursive lock, semaphore is the upper packaging and implementation!
2. @ synchorized analysis
2.1 Analysis Procedure
@synchrized is one of the most developed mutex recursive locks we use everyday, for example to define singletons and so on. Let’s take a look at the underlying implementation using Clang compilation
To simplify the
The main ones are objc_sync_Enter and objc_sync_exit.
- Use assembly validation below
2.2 objc_sync_enter & objc_sync_exit analysis
objc_sync_enter
The source of
judgeobj
Whether it isnil
fornil
Do nothing; Don’t fornil
Through theid2data
To obtainSyncData
And then data is locked.
objc_sync_exit
Source:Exit and enter similar, default int = 0, judgeobj
Whether it isnil
fornil
Do nothing; Don’t fornil
Through theid2data
To obtainSyncData
, determine whether there is lock data, if there is noresult
For the mistake. An error message is returned after an attempt is made to unlock the account.
2.2.1 SyncData analysis
SyncData is a structure containing hash linked lists, object encapsulation, and the number of threads that use locks to represent the ability to multithread, recursive properties.
SyncCache is also a structure that contains information about the number of threads created, the number of threads used, and the current thread. SyncCacheItem is the data that contains the lock and the number of times the thread locked.
在id2data
In thelistp
Its structure is in the form of a hash zipper.
Look at the list:So that’s why it’s on the simulator, right@synchorized
The efficiency of theIt's slower than the real thing
, because in the real machine to store the lock againlist
Size only8
And the simulator has64
So it takes more time. Is 8 real machines enough? It will take place when it’s finishedThe release of
So don’t worry, if not enough should be carried outWaiting for the
.
2.2.2 id2data analysis
1. Check whether TLS (thread local storage) is supported. 2. Second look at the thread cache, cache in 3. The last does not indicate the first entry.
We use code to follow a flow
Lock recursively in the main thread
- First time in and out
SUPPORT_DIRECT_THREAD_KEYS
Of the current threadSyncData
为Null
Because this is the first time that the corresponding lock information is not stored.
Fetch threadSyncCache
Is alsoNULL
In the same way, no information about the corresponding lock is cached for the first time.
The first operation initializes SyncData and assigns threadCount to 1 and object as well as the Listp hash list, using header notation and marking thracount = 1.
saveSyncData
To the current thread and savelockcount =1
- The second time
SyncData
To save in the current TLS, go through the following process
Because it isobjc_sync_enter
sowhy
isACQUIRE
, the number of locks+ 1
, stores the number of locks to the current thread. The third time is the same as the second time.
objc_sync_exit
similar
- Multithreaded asynchrony
- Multithreaded asynchronous recursion
- Synchronize recursion cases
There are three cases of SyncData in ID2Data:
- First time in, no lock, initialization
SyncData
And assignmentthreadCount
for1
, the storagelockCount
totls
. - Second time in, support
tls
To obtaintls
Stored inSyncData
,lockCount++
Operation to store the number of locks to the current thread. - Second entry, not supported
tls
, use thecache
Obtain, check alreadyOwned by the lock
theEach thread
Whether the cache matches the object, if solockCount++
3. Summary
2 storage methods TLS and cache, mutual exclusion, recursion, and multithreading supported by threadCount and lockCount. Daily use frequency is relatively high, we do not need to manually unlock, and the efficiency of the real phone has been optimized. Do not use non-OC objects as locked objects, because the parameter of object is ID, the locked object should pay attention to scope, to prevent the occurrence of wild pointer in multi-threading.
- To be continued…