• IOS multithreading, spin locks and mutex details
  • NSThread for iOS multithreading
  • NSOperation for iOS multithreading
  • IOS Multithreading GCD

preface

Apple official documentation – Multithreading

Multithreading technology is widely used in the process of mobile terminal development. Only by deep understanding of the principle of the processor and combining with business thinking, can we maximize the ability of concurrent programming in the limited thread control API, and also easily detect the possible security problems in the code and solve them gracefully.

1. Thread description

1.1 process

Process: refers to an application program that is running in the system. Each process is independent of each other and runs in its dedicated and protected memory space (for example, Xcode and wechat will open two processes).

  • Processes are the basic unit for allocating resources

1.2 the thread

  • Thread (thread): in order for a process to perform a task, it must have threads (each process must have at least one thread), in which all tasks of a process (program) are executed.
  • Serialization of threads: The execution of tasks in a thread is serial. If multiple tasks are to be executed in a thread, they can only be executed sequentially one by one, that is, each thread can only execute one task at a time
  • A thread is the smallest unit of Program execution flow. A thread consists of: unique ID, Program Counter, register set, stack. The same process can have multiple threads that share global variables and heap data for the process.

1.3 a multithreaded

Multithreading: multiple threads can be opened in a process, and each thread can perform different tasks in parallel (at the same time). Multithreading technology can improve the execution efficiency of the program

  • Address space: Threads of the same process share the address space of the same process, while processes are independent of each other.

  • Resource ownership: Threads in the same process share the resources of the same process, such as memory, I/O, and CPU, but resources between processes are independent

  • 1: a process crash in protected mode does not affect other processes, but a thread crash kills the entire process. So multi-processing is more robust than multi-threading.

  • 2: Process switching consumes large resources and is efficient, so it is better to use thread than process when frequent switching is involved. Also, if you require concurrent operations that share variables at the same time, use threads instead of processes

  • 3: Execution process: Each independent process has a program run entry, sequential execution sequence and program entry. However, threads cannot execute independently and must depend on the application, which provides multiple thread execution control.

  • Thread is the basic unit of processor scheduling, but process is not.

  • 5: Threads have no address space. Threads are contained in the process address space

  • Principle of multi-threading:

The CPU can process only one thread at a time, and only one thread is working (executing) (2). When multiple threads execute concurrently, the CPU quickly switches between multiple threads (3). If the CPU schedules threads fast enough, it creates the illusion that multiple threads are executing concurrently

  • Thread Pool Principle

  • What happens if there are very, very many threads?

(1). The CPU will be scheduled between N threads, and the CPU will be exhausted and consume a lot of CPU resources (2). Each thread is scheduled to execute less often (thread execution efficiency is reduced)

  • Advantages of multithreading

  • Can improve the execution efficiency of the program

  • Appropriately improve resource utilization (CPU, memory utilization)

  • Disadvantages of multithreading

  • There are costs associated with creating a thread (the main costs for iOS include kernel data structure (about 1KB), stack space (512KB child thread, 1MB main thread, setStackSize: set, but must be a multiple of 4K, and minimum 16K), creating a thread takes about 90ms to create)

  • If a large number of threads are opened, the performance of the program will be reduced

  • The more threads there are, the more overhead the CPU has on scheduling threads

  • Programming is more complex: communication between threads, data sharing between multiple threads

1.4 Relationship between processes and threads

1.5 Thread life cycle

  • New: Instantiate the thread object
  • Ready: sent to the thread objectstartMessage, thread object is added to the schedulable thread pool waitCPUscheduling
  • Run:CPUResponsible for scheduling the execution of threads in the schedulable thread pool. Before the thread completes execution, the state may be inreadyandrunBack and forth between.readyandrunBetween states byCPUResponsible, the programmer can’t intervene.
  • Blocking: When a predetermined condition is met, sleep or locking can be used to block thread execution.
  • Death: Normal death, thread execution completed. Unnatural death, aborting execution inside a thread/aborting a thread object in the main thread when a condition is met.

1.6 the thread andrunloopThe relationship between

  • 1.runloopIt’s one to one with threads, onerunloopFor a core thread, why is it core, becauserunloopCan be nested, but there can only be one core, and their relationships are stored in a global dictionary.
  • 2.runloopIs to manage threads, when threadsrunloopWhen enabled, the thread will go to sleep after completing the task and will be woken up to execute the task.
  • 3.runloopIs created on the first fetch and destroyed at the end of the thread.
  • 4. For the main thread,runloopIt is created by default as soon as the program starts.
  • 5. For child threads,runloopIt is lazy to load and is only created when we use it, so take care when using a timer on a child thread: make sure that the child thread isrunloopWas created, or the timer will not be called back.

2. IOS multithreading scheme

3. Spin locks and mutex

3.1 the mutex

  • Definition: When the previous thread’s task is not finished (locked), the next thread will go to sleep and wait for the task to complete until the previous thread completes, the next thread will automatically wake up and start to cherish the task

  • Principle of mutex: the thread will go from sleep(lock)–> RUNNING (unlock), there are context switching in the process (actively give time slice, the thread sleep, wait for the next wake up), CPU preemption, signal sending and other overhead.

  • The mutex sleeps: When a locked resource is accessed, the caller thread sleeps so that the CPU can schedule other threads to work. Until the locked resource releases the lock. The dormant thread is awakened.

Mutex :@synchronized,NSLock, pthread_mutex, NSConditionLock, NSCondition, NSRecursiveLock

3.2 the spin lock

  • Definition: A lock used to protect a resource shared by multiple threads. With general mutex (mutexThe difference is that the spin lock is busy waiting when it tries to acquire the lock (busy waiting) in the form of a constant loop to check whether the lock is available. When the task of the previous thread is not finished, the next thread is inHas been waiting forState that does not sleep until the last execution is complete.
  • How spinlocks work: Threads are alwaysrunning(lock — > unlock), endless loop (busy, etcdo-while) detect the flag bit of the lock, the mechanism is not complex.
  • Advantages: Spin locks do not cause callers to sleep, so no thread scheduling occurs,CPUTime-consuming operations such as time slice rotation. Spin locks are far more efficient than mutex locks if they can be acquired in a short amount of time. Suitable for programs with short locks.
  • Disadvantages: The spin lock is always occupiedCPUIn the absence of a lock, the spin lock is always running (busy, etc., query), occupiedCPUIf you can’t get the lock in a short time, it will definitely make the CPU less efficient. Spin locks do not make recursive calls.

Spin locks: Atomic, OSSpinLock, dispatch_semaphoRE_t

expandatomicwithsynchronized

It’s the default property for multithreaded development! In setter methods for properties, only add a lock (spin lock) to ensure that only one thread writes to a property at a time, and that only one thread writes many reads at a time. High performance!

Note: In OC, if you also override setter & getter methods, the system no longer provides _ member variables, and requires the @synthesize name instruction to take the individual name :_name

Simulating atomic code

#pragma mark - (NSString *)name {return _name; } - (void)setName:(NSString *)name {/** ** */ @synchronized (self) { _name = name; }}Copy the code

setterMethod source code:

static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy) { if (offset == 0) { object_setClass(self, newValue); return; } id oldValue; id *slot = (id*) ((char*)self + offset); if (copy) { newValue = [newValue copyWithZone:nil]; } else if (mutableCopy) { newValue = [newValue mutableCopyWithZone:nil]; } else { if (*slot == newValue) return; newValue = objc_retain(newValue); } if (! atomic) { oldValue = *slot; *slot = newValue; } else {// If atomic, lock spinlock_t& slotlock = PropertyLocks[slot]; slotlock.lock(); oldValue = *slot; *slot = newValue; slotlock.unlock(); } objc_release(oldValue); }Copy the code

getterMethods the source code

id objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) { if (offset == 0) { return object_getClass(self); } // Retain release world id *slot = (id*) ((char*)self + offset); if (! atomic) return *slot; // Atomic retain release world spinlock_t& slotlock = PropertyLocks[slot]; slotlock.lock(); id value = objc_retain(*slot); slotlock.unlock(); // for performance, we (safely) issue the autorelease OUTSIDE of the spinlock. return objc_autoreleaseReturnValue(value); }Copy the code

See GitHub-> Multithreading for the full code


If there are shortcomings, welcome to correct, if you feel good writing, remember to give a thumbs up!