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 andRunloopThe relationship between

  • The thread andRunloopIt’s one to one, oneRunloopThere’s a core thread, why is it core, becauseRunloopCan be nested, but there is only one core, and their correspondence is stored in a global dictionary
  • RunloopIt 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).
  • RunloopIt is created on the first fetch and destroyed at the end of the thread
  • The main thread of theRunloopIt is created by default when the program starts
  • The child threadRunloopIs lazy-loaded and is created only when used, so used in child threadsNSTimerTake care to ensure that the child threadRunloopCreated otherwiseNSTimerIt 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 iOSSeveral threads in

In iOS, there are several ways to use multithreading:

  1. pthread: that is,POSIX Thread, abbreviated asPthread, is threadPOSIXStandard is a set of universal multithreadingAPI, can be inUnix/Linux/WindowsSuch as cross-platform use.iOSIs basically not used in.
  1. NSThread: Apple encapsulates the object-oriented thread class, can directly manipulate the thread, compared toGCD.NSThreadMore 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.
  1. GCDFull name:Grand Central DispatchBy theCLanguage implementation, apple’s solution to multi-core parallel computing,CGDWill automatically utilize moreCPUThe kernel, which automatically manages the thread lifecycle, the programmer just needs to tellGCDTasks that need to be performed without writing any code to manage threads.GCDIs alsoiOSThe most frequently used multithreading technology.
  1. NSOperationBased on:GCDEncapsulation of object-oriented multithreading technology, often withNSOperationQueueUse, high frequency of use.

Thread pools

  • Thread Pool

    A pool that manages the life cycle of multiple threads.iOSThread pools are not directly touched in development becauseGCDThread pool management is already included, we just need to go throughGCDGet the thread to perform the task.
  • The life cycle of a thread

    The life cycle of a thread includescreatereadyrundeathWith 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 sourcesThis 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:

  1. NSPortObject must be added to the thread that is receiving the messageRunloopIn the
  1. The object implementation that receives the messageNSPortDelegateOf 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.