Processes and threads
1.1 process
Process is the basic unit of resource allocation and scheduling in the system. On iOS, an App running instance is a process, and each process has its own address segment in the memory.
1.2 the thread
A thread is the basic execution unit of a process. All tasks in a process are executed in a thread. Therefore, there must be at least one thread in a process. By default, iOS apps start a main thread, also known as the UI thread.
1.3 Relationship between processes and threads
- Address space: The address space in the same process can be shared by multiple threads in the same process, but the address space between processes is independent
- Resource ownership: Resources in the same process can be shared by all threads in the process, such as memory, I/O, CUP, etc., but resources between processes are independent of each other
- The crash of any thread in a process can cause the entire process to crash, but the crash of a process does not affect another process
- A process can be seen as a container for threads. Each process has an entry point for the program to run, but threads cannot run independently and must depend on the process
1.4 the thread andRunloop
The relationship between
- The thread and
Runloop
It’s one to one, oneRunloop
There’s a core thread, why is it core, becauseRunloop
Can be nested, but there is only one core, and their correspondence is stored in a global dictionary Runloop
It is used to manage threads. When they finish executing a task, they go to sleep and wake up when a task comes in and start executing it (event-driven).
Runloop
It is created on the first fetch and destroyed at the end of the thread- The main thread of the
Runloop
It is created by default when the program starts
- The child thread
Runloop
Is lazy-loaded and is created only when used, so used in child threadsNSTimer
Take care to ensure that the child threadRunloop
Created otherwiseNSTimer
It won’t go into effect.
Two, multithreading
2.1 Concepts and Principles
A process can be concurrent with multiple threads to perform their respective tasks at the same time, called multithreading. Time-sharing operating system will reduce the CPU time length is divided into basic same time interval, the name is “time”, in a time slice, the CPU can only handle one thread of a task, for a single core CPU, in different time to perform the tasks in different threads, are formed multiple tasks at the same time perform “illusion” :

In the figure above, the CPU starts to execute the task in thread 3 at the time slice T3, but before the task is finished, it arrives at T4, starts to execute the task in thread 4, completes the task in thread 4 in the time slice T4, and continues to execute the task in thread 3 at t5. Now all are multi-core CPUS, each core can handle tasks individually, to achieve “true” multi-threading, but an App is often dozens of concurrent threads, so each core still implement multi-threading in the above principle.
2.2 iOS
Several threads in
In iOS, there are several ways to use multithreading:
pthread
: that is,POSIX Thread
, abbreviated asPthread
, is threadPOSIX
Standard is a set of universal multithreadingAPI
, can be inUnix/Linux/Windows
Such as cross-platform use.iOS
Is basically not used in.
NSThread
: Apple encapsulates the object-oriented thread class, can directly manipulate the thread, compared toGCD
.NSThread
More efficient, created by the programmer, when the task in the thread is finished, the thread will automatically exit, programmers can also manually manage the life cycle of the thread. Use frequency is low.
GCD
Full name:Grand Central Dispatch
By theC
Language implementation, apple’s solution to multi-core parallel computing,CGD
Will automatically utilize moreCPU
The kernel, which automatically manages the thread lifecycle, the programmer just needs to tellGCD
Tasks that need to be performed without writing any code to manage threads.GCD
Is alsoiOS
The most frequently used multithreading technology.
NSOperation
Based on:GCD
Encapsulation of object-oriented multithreading technology, often withNSOperationQueue
Use, high frequency of use.
Thread pools
- Thread Pool
A pool that manages the life cycle of multiple threads.iOS
Thread pools are not directly touched in development becauseGCD
Thread pool management is already included, we just need to go throughGCD
Get the thread to perform the task.
- The life cycle of a thread
The life cycle of a thread includescreate
—ready
—run
—death
With these four phases, we can control the life cycle of the thread by blocking, exiting, and so on.
4. Communication between threads
4.1 Communication modes between several threads
In the interview, often asked by the interviewer how threads communicate, many children will answer in the child thread to get data, switch back to the main thread to refresh the UI, then please go home and other messages. Apple’s official documentation lists several ways threads can communicate with each other:

The table above is in descending order of technical complexity, with the latter two only available in OS X.
Direct messaging
: This is very familiar-performSelector:
Series.
Global variables...
: Directly through global variables, shared memory and other ways, but this way will cause resource robbery, involving thread safety issues.
Conditions
: a special type of lock, conditional lock, is used to make a thread wait (wait
), the thread will block and go to sleep, signaling the same conditional lock in another thread (single
), the waiting thread will be woken up to continue executing the task.
Run loop sources
: CustomizeRun loop sources
This will be studied separately in a later articleRun loop
.
Ports and sockets
: Implements thread communication through ports and sockets.
4.2 Example of Communication between threads
The first two are familiar, and the third conditional lock is not difficult to use. Here is a Demo of interthread communication using Port. Create an iOS project and create a class AvatarDownloader to simulate the process of downloading the avatar in a child thread and refreshing the UI in the main thread
// AvatarDownloader.h extern NSString * const AvatarDownloaderUrlKey; extern NSString * const AvatarDownloaderPortKey; @interface AvatarDownloader : NSObject - (void)downloadAvatarInfo:(NSDictionary *)info; @end // AvatarDownloader.m NSString * const AvatarDownloaderUrlKey = @"Url"; NSString * const AvatarDownloaderPortKey = @"Port"; @interface AvatarDownloader ()<NSMachPortDelegate> @property (nonatomic, strong) NSPort *completePort; @property (nonatomic, strong) NSMachPort *downloaderPort; @end @implementation AvatarDownloader - (instancetype)init { if (self = [super init]) { self.downloaderPort = [[NSMachPort alloc] init]; self.downloaderPort.delegate = self; } return self; } - (void)downloadAvatarInfo:(NSDictionary *)info { @autoreleasepool { NSLog(@"download thread: %@", [NSThread currentThread]); NSString *url = info[AvatarDownloaderUrlKey]; NSLog(@"download url: %@", url); self.completePort = info[AvatarDownloaderPortKey]; Sleep (2); UIImage *img = [UIImage imageNamed:@"avatar.jpg"]; NSData *data = UIImageJPEGRepresentation(img, 1); NSLog(@"download complete"); NSMutableArray *components = @[data].mutableCopy; [self.completePort sendBeforeDate:[NSDate date] msgid:1 components:components from:self.downloaderPort reserved:0]; } } #pragma mark - NSMachPortDelegate - (void)handlePortMessage:(NSPortMessage *)message { NSLog(@"downloader handlePortMessage: %@", [NSThread mainThread]); NSArray *components = [(id)message valueForKey:@"components"]; NSData *data = components[0]; NSString *msg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"response msg from receiver: %@", msg); }Copy the code
The root controller code is as follows:
// ViewController.m #import "ViewController.h" #import "AvatarDownloader.h" NSString * const AVATAR_URL = @ http://img3.imgtn.bdimg.com/it/u=1559309274, "2399850183 & FM = 26 & gp = 0. JPG"; @interface RootViewController ()<NSMachPortDelegate> @property (weak, nonatomic) IBOutlet UIImageView *imageView; @property (nonatomic, strong) NSMachPort *mainPort; @property (nonatomic, strong) AvatarDownloader *downloader; @end @implementation RootViewController - (void)viewDidLoad { [super viewDidLoad]; Self.mainport = [[NSMachPort alloc] init]; self.mainPort = [[NSMachPort alloc] init]; self.mainPort.delegate = self; [[NSRunLoop currentRunLoop] addPort:self.mainPort forMode:NSDefaultRunLoopMode]; NSDictionary *info = @{AvatarDownloaderUrlKey : AVATAR_URL, AvatarDownloaderPortKey : self.mainPort}; self.downloader = [[AvatarDownloader alloc] init]; [NSThread detachNewThreadSelector:@selector(downloadAvatarInfo:) toTarget:self.downloader withObject:info]; } #pragma mark - NSPortDelegate - (void)handlePortMessage:(NSPortMessage *)message { NSLog(@"handlePortMessage: %@", [NSThread currentThread]); NSArray *array = [(id)message valueForKey:@"components"]; NSData *data = array[0]; UIImage *avatar = [UIImage imageWithData:data]; self.imageView.image = avatar; NSData * responseMsg = [@ "avatar has received" dataUsingEncoding: NSUTF8StringEncoding]; NSMutableArray *components = @[responseMsg].mutableCopy; NSPort *remotePort = [(id)message valueForKey:@"remotePort"]; // The downloader thread has been destroyed, so send a message to remotePort, Have to add it to survive in the runloop [[NSRunLoop currentRunLoop] addPort: remotePort forMode: NSDefaultRunLoopMode]; [remotePort sendBeforeDate:[NSDate date] msgid:2 components:components from:self.mainPort reserved:0]; } @endCopy the code
Use of NSPort:
NSPort
Object must be added to the thread that is receiving the messageRunloop
In the
- The object implementation that receives the message
NSPortDelegate
Of the agreement-handlePortMessage:
Method to get the message content
After running the program, the console output is as follows:
Download thread: <NSThread: download thread: <NSThread: 0x600001E1E740 >{Number = 6, Name = (null)} 2020-02-23 00:11:43.449342+0800 TestObjC[3140:208871] Download URL: http://img3.imgtn.bdimg.com/it/u=1559309274, & FM = 26 & gp = 0. 2399850183. JPG 00:11:45 2020-02-23 486259 + 0800 TestObjC[3140:208871] Download Complete 2020-02-23 00:11:45.486600+0800 TestObjC[3140:208701] handlePortMessage: <NSThread: 0x600001e49e00>{number = 1, Name = main} 2020-02-23 00:11:45.492472+0800 TestObjC[3140:208701] downloader handlePortMessage: <NSThread: 0x600001e49e00>{number = 1, Name = main} 2020-02-23 00:11:45.492666+0800 TestObjC[3140:208701] Response MSG from receiver: The avatar has been receivedCopy the code
MainPort is added to the main thread’s Runloop, and a new thread downloads the avatar. When the avatar is downloaded, a message is sent through the mainPort. There is no manual thread switch, but the controller callback is in the main thread, thus completing the communication between threads.