For more practical details seeDemo

This article introduction

Some relevant summaries (synchronous, asynchronous, parallel and serial concepts, comparison of GCD and NSOperation)

NSThread: NSThread: NSThread: NSThread: NSThread: NSThread: NSThread: NSThread: NSThread: NSThread: NSThread: NSThread: NSThread: NSThread: NSThread: NSThread

Synchronous, asynchronous, parallel, serial

  1. Synchronization and asynchrony determine whether to start a new thread. Synchronization performs tasks in the current thread and does not have the ability to start a new thread. Asynchrony performs tasks in a new thread and has the ability to start a new thread.
  2. Parallelism and serialization determine how tasks are executed. Concurrent Execution of multiple tasks concurrently (simultaneously). Serial: After one task is executed, the next task is executed.

Comparison between GCD and NSOperation:

  • The GCD — > iOS 4.0

(1) Add the task (block) to the queue(serial/concurrent (global)), specify the method of executing the task (synchronous (block)/ asynchronous) (2) get the dispatch_get_main_queue(). Inter-thread communication (3) NSOperation cannot be executed at one time, delayed execution, scheduling group (OP is relatively complex) (4) It provides more control ability and low-level functions that cannot be used in operation queue

  • NSOperation —-> iOS 2.0 (Later Apple reworked the underlying NSOperation)

(1) add the operation (asynchronous execution) to the queue (concurrent/global) (2) [NSOperationQueue mainQueue] mainQueue. Tasks added to the main queue are executed on the main thread (3) provide some things that GCD is not easy to implement, such as “maximum concurrency”, dependencies, pause/continue – suspend, cancel all tasks

  • Contrast:

(1) GCD is a pure C API, NSOperationQueue is based on the OC version of GCD package (2) GCD only supports FIFO queues, NSOperationQueue can easily adjust the order of execution and set the maximum number of concurrent operations (FIFO is first in first out). (4) NSOperationQueue supports KVO(key-value observer), You can listen to whether operation isExecuted (isExecuted), whether operation is cancelled (isCanceld), whether operation isExecuted (isFinished), whether operation is cancelled (isCanceld). Because it has to be transformed.)

  • When do you choose to use GCD and when do you choose NSOperation in your project? NSOperation: Between tasks are dependent on, or to monitor tasks used in the implementation of project has the advantage that it is a highly abstract of thread, can make the program structure is better, subclassing NSOperation design train of thought has the advantages of object-oriented (reuse, encapsulation), makes multithreading support, and simple interface, should be used in complex projects. · GCD: The advantage of using GCD in projects without too much dependence between tasks is that GCD itself is very simple and easy to use. For uncomplicated multi-threaded operations, it will save the amount of code, while the use of Block parameter will make the code more readable, so it is recommended to use it in simple projects.

First, some multithreading related

Principle of multithreading

  • The CPU can only process one thread at a time, and only one thread is working (executing)
  • Concurrent execution of multiple threads is when the CPU quickly switches between multiple threads.
  • What happens if there are too many threads?
    1. The CPU will be scheduled between N threads, the CPU will be exhausted, consuming a lot of CPU resources
    2. Each thread is scheduled to execute less often (thread execution efficiency is reduced)

Advantages and disadvantages of multi-threading

Advantages:

  • Can improve the execution efficiency of the program appropriately
  • Appropriately improve resource utilization (CPU, memory utilization)

Disadvantages:

  • Starting threads occupies a certain amount of memory space (by default, the main thread occupies 1 MB and child threads occupy 512KB. If a large number of threads are enabled, a large amount of memory space will be occupied and the program performance will be degraded).
  • The more threads there are, the more overhead the CPU has on calling threads
  • The program design is more complex, such as communication between threads, multithreaded data sharing

Multi-thread implementation scheme

Second, multi-threaded -GCD

chart

The GCD introduction

Grand Central Dispatch, pure C language, provides many powerful functions

  • Advantage:

    1. Apple’s solution to multi-core parallel computing
    2. – GCDS automatically utilize more CPU cores (such as dual core, quad core)
    3. GCD automatically manages thread lifecycles (thread creation, task scheduling, thread destruction)
    4. The programmer only needs to tell the COMMUNIST party what task it wants to perform, without writing any thread management code
  • There are two core concepts in GCD:

    1. Task: What operation is performed
    2. Queue: Used to store tasks
  • There are two steps to using GCD:

    1. Customize tasks: Determine what you want to do
    2. Add tasks to queue: GCD automatically removes tasks from the queue and puts them into the corresponding thread for execution. Task fetching follows the FIFO principle of queue (first in, first out, last in, last out)
  • Perform tasks – GCD has two functions for performing tasks

    1. Dispatch_sync Synchronization. Dispatch_async: asynchronous
    2. Difference between synchronous and asynchronous Synchronous: A task can be executed in the current thread but cannot be started on a new thread. Asynchronous: A task can be executed in a new thread and a new thread can be started
  • Type of queue:

GCD queues can be divided into two types: · Concurrent queue (1) Tasks in a queue are usually executed concurrently (2) Multiple tasks can be executed concurrently (automatically enabling multiple threads to execute tasks simultaneously) (3) Concurrency only works with asynchronous (dispatch_async) functions · Serial queue: (1) Tasks in the queue are only executed sequentially (2) Tasks are executed one after another (after one task is executed, the next task is executed)

  • How is it implemented inside GCD?

(1) The core of iOS and OS X is the XNU kernel, GCD is implemented based on XNU kernel. (2) ALL GCD apis are in libDispatch library. (3) GCD’s low-level implementation mainly includes Dispatch Queue and Dispatch Source · Dispatch Queue: · Dispatch Source: Event handling (MACH port sending,MACH port receiving, detection of 10 events related to process, etc.)

  • The execution effect of various queues Note:Adding tasks to the current serial queue using sync will block the current serial queue

The basic use

  1. The difference between a global queue and a parallel queue is that (1) the global queue does not need to be created, but can be used to GET directly. (2) The execution effect of the two queues is the same. (3) The global queue has no name and cannot be confirmed during debugging
  2. Global queues: GCD already provides global concurrent queues by default for use by the entire application. You do not need to create them manually
Dispatch_queue_t dispatch_get_global_queue(dispatch_queue_priority_t priority, unsigned long flags); Dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); Priority of global concurrent queue #define DISPATCH_QUEUE_PRIORITY_HIGH 2 // high #define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // Default (middle) #define DISPATCH_QUEUE_PRIORITY_LOW (-2) // low #define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MINCopy the code

Dispatch_queue_t q = dispatch_queue_create(“queuename”, DISPATCH_QUEUE_CONCURRENT); 4. Serial queues

Dispatch_queue_t dispatch_queue_create(const char *label, // queue name dispatch_queue_attr_attr); Dispatch_queue_t t = dispatch_queue_create("queuename",DISPATCH_QUEUE_SERIAL);Copy the code
  1. Return from child thread to main thread
Dispatch_async (dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ Dispatch_async (dispatch_get_main_queue(), ^{// return to main thread, perform UI refresh}); });Copy the code
  1. One-time code
static dispatch_once_t onceToken; Dispatch_once (&onceToken, ^{// only execute code once(thread-safe by default)});Copy the code

GCD Advanced: dispatch_group

  • Application scenario: During development, when multiple network requests are completed (the event length of each network request is not certain), users will be notified uniformly. For example: download novels: Romance of The Three Kingdoms, a Dream of red Mansions, water Margin
    Dispatch_group_t group = dispatch_group_create(); Dispatch_queue_t queue = dispatch_get_global_queue(0, 0); Queue dispatch_group_async(group, queue, ^{NSLog(@" A-- %@", [NSThread currentThread]); }); Dispatch_group_async (group, queue, ^{NSLog(@ --%@, [NSThread currentThread]); }); Dispatch_group_async (group, queue, ^{NSLog(@ --%@, [NSThread currentThread]); }); // dispatch_group_notify(group, queue, ^{NSLog(@" download completed, please see %@", [NSThread currentThread]); // asynchronous //}); // Note: ^{// update UI on main thread NSLog(@" download complete, See %@", [NSThread currentThread]); // asynchronous});Copy the code

GCD Advanced: dispatch_group_Enter, dispatch_group_leve

Dispatch_group_enter: dispatch_group_leave: “Dispatch_group_wait” : “dispatch_group_notify” : “dispatch_group_wait” : “dispatch_group_notify” : “dispatch_group_wait” : “dispatch_group_notify” : “dispatch_group_wait” : “dispatch_group_notify” : It is called at the end as long as the task is complete

- (void)gcdGroupEnterAndLeave { dispatch_group_t group = dispatch_group_create(); dispatch_group_enter(group); Dispatch_group_async (dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ Dispatch_group_leave (group);}]; }); dispatch_group_enter; Dispatch_group_async (dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ }]; dispatch_group_leave }); dispatch_group_enter(group); Dispatch_group_async (dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ Dispatch_group_leave (group);}]; }); Dispatch_group_notify (group, dispatch_get_main_queue(), ^{// NSLog(@" all tasks completed, refresh interface "); }); }Copy the code

GCD Advanced: Multiple network requests are executed sequentially using semaphore

Each pass is dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER), at which point the thread waits and blocks the current thread until dispatch_semaphore_signal(sem) is called

NSString *str = @"https://juejin.im/editor/posts/5c9841cd5188252d5a14992a";
NSURL *url = [NSURL URLWithString:str];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLSession *session = [NSURLSession sharedSession];

dispatch_semaphore_t sem = dispatch_semaphore_create(0);
for (int i=0; i<10; i++) {
    
    NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
        NSLog(@"%d---%d",i,i);
        dispatch_semaphore_signal(sem);
    }];
    
    [task resume];
    dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
}

dispatch_async(dispatch_get_main_queue(), ^{
    NSLog(@"end");
});
Copy the code

GCD Advanced: dispatch_barrier_(a)sync

First is Apple Documentation’s explanation of dispatch_barrier_Async

  • Dispatch barriers allow developers to create a synchronization point in a parallel queue and are also used to protect resources from being used at the same time in a race.

In parallel asynchronous tasks: Barrier_sync tasks are executed concurrently, and tasks after the syncBarrier must wait for tasks in the main thread to complete before executing them. Barrier_async tasks are executed concurrently. Barrier_async tasks must wait for barrier_Async tasks to complete before executing them, but the Barrier cannot block tasks on the main thread

  • Create a thread-safe NSMutableArray

NSMutableArray itself is thread unsafe. Simply put, thread safety means that multiple threads access the same code without exceptions or crashes. Writing thread-safe code relies heavily on thread synchronization. 1. Reasons not to use atomic modifier properties for thread safety: 1) Atomic memory management semantics only guarantee that setter and getter methods are atomic, locking setter methods is thread-safe, but other methods of properties, such as adding/removing elements from groups of properties, are not atomic operations, so they are not thread-safe. 2) Atomic methods are thread-safe for getter and setter methods, but at a cost of execution many times slower than nonatomic methods (some say 10-20 times slower). In short: Use nonatomic to decorate the NSMutableArray object, and use locks and dispatch_queue to keep the NSMutableArray object thread-safe. NSMutableArray: Effective Objective-C 2.0… In the book, article 41: Use more dispatch queues and less synchronization locks. It is pointed out that data synchronization can be ensured by using the serial synchronization queue, in which read and write operations are arranged in the same queue. Through the concurrent queue, combined with the barrier of GCD, data synchronization can not only achieve thread safety, but also more efficient than the serial synchronization queue.

  • An example of NSMutableArray’s read-write security problem is dispatch_barrier_async, which waits for all functions preceding barrier to complete before executing all functions following barrier. Need to be combined with the created concurrent queue.
    - (void)barrier {// Use dispatch_queue_t Queue = with the concurrent Dispatch Queue generated by the dispatch_queue_create function dispatch_queue_create("12312312", DISPATCH_QUEUE_CONCURRENT); Dispatch_async (queue, ^{NSLog(@"1 read %@", [NSThread currentThread]); }); Dispatch_async (queue, ^ {NSLog (@ "-- -- -- -- -- -- 2 read % @", [NSThread currentThread]); }); Dispatch_barrier_async (queue, ^{NSLog(@"----barrier write -----%@", [NSThread currentThread]); }); Dispatch_async (queue, ^ {NSLog (@ "-- -- -- -- -- -- 3 read % @", [NSThread currentThread]); }); Dispatch_async (queue, ^ {NSLog (@ "-- -- -- -- -- -- 4 read % @", [NSThread currentThread]); }); }Copy the code

Several task nesting:

  • Starting asynchronous tasks in the main queue does not start a new thread but still executes the code in the block in the main thread. Why doesn’t the thread block?

The main queue starts asynchronous tasks. It does not start new threads, but it degrades the priority of asynchronous tasks and executes them on the main thread when it is idle.

  • Why does starting a synchronization task in the main queue block the thread?

Start the synchronization task in the main queue, because the main queue is a serial queue, the threads in the main queue are sequential, finish one thread before the next thread, and the main queue is always only one thread, the main thread will not finish, because it is infinite loop, unless the application is closed. So if you start a synchronization task on the main thread, the synchronization task will try to grab executing resources, but the main thread task is doing something and won’t let go. Both of them have high priorities and eventually cause a deadlock, blocking the thread.

  • Note: the following code is executed in the order 1111 2222
- (void)main_queue_deadlock { dispatch_queue_t q = dispatch_get_main_queue(); NSLog(@"1111"); Dispatch_async (q, ^{NSLog(@" async ", [NSThread currentThread]); }); NSLog(@"2222"); // dispatch_sync(q, ^{NSLog(@" primary queue sync %@", [NSThread currentThread])); / /}); }Copy the code
  • After asynchronous tasks are enabled on the serial queue, synchronization tasks are nested, causing deadlocks. Procedure
dispatch_queue_t q = dispatch_queue_create("test", DISPATCH_QUEUE_SERIAL); Dispatch_async (q, ^{NSLog(@" async %@", [NSThread currentThread]); Threads in the serial queue have execution order. The synchronization task started in the serial queue can be executed only after the asynchronous task started in the serial queue is completed. The above asynchronous task is not finished until the following braces are executed, and the following synchronous task is already preempting resources, which causes a deadlock. Dispatch_sync (q, ^{NSLog(@" %@", [NSThread currentThread]); }); });Copy the code
  • After synchronization tasks are nested in a serial queue, a deadlock occurs. Procedure
dispatch_queue_t q = dispatch_queue_create("test", DISPATCH_QUEUE_SERIAL); Dispatch_sync (q, ^{NSLog(@" %@", [NSThread currentThread]); Threads in the serial queue are executed in sequence. The synchronization task started in the serial queue can be executed only after the synchronization task started in the serial queue is completed. The synchronization task above is not completed until the curly braces below are completed, and the synchronization task below is already preempting resources, which causes a deadlock. Dispatch_sync (q, ^{NSLog(@" %@", [NSThread currentThread]); }); }); NSLog(@" sync task %@", [NSThread currentThread]);Copy the code
  • The serial queue does not cause deadlock when nesting asynchronous tasks after synchronization tasks are enabled
  • A deadlock, for example,
    NSLog(@" Perform task 1"); // dispatch_queue_t queue = dispatch_queue_create(@"myqueue", DISPATCH_QUEUE_SERIAL); // dispatch_queue_t queue2 = dispatch_queue_create(@"myqueue2", DISPATCH_QUEUE_CONCURRENT); // dispatch_queue_t queue3 = dispatch_queue_create(@"myqueue3", DISPATCH_QUEUE_SERIAL); Dispatch_async (queue, ^{NSLog(@" perform task 2"); / / will cause a deadlock / / dispatch_sync (queue, ^ {/ / NSLog (@ "mission 3"); / /}); ^{NSLog(@" execute task 3"); }); Queue3 ^{NSLog(@" perform task 3"); NSLog(@" perform task 3"); }); NSLog(@" Perform task 4"); }); NSLog(@" Perform task 5");Copy the code
  • Example of task nesting on parallel queues
dispatch_queue_t q = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT); // dispatch_sync(q, ^{NSLog(@"1 %@", [NSThread currentThread]); dispatch_sync(q, ^{ NSLog(@"2 %@", [NSThread currentThread]); dispatch_sync(q, ^{ NSLog(@"3 %@", [NSThread currentThread]); }); }); dispatch_async(q, ^{ NSLog(@"4 %@", [NSThread currentThread]); }); NSLog(@"5 %@", [NSThread currentThread]); }); // The result is 12345 or 12354Copy the code

In parallel queues, synchronous tasks are enabled in an order of execution. Only asynchronous tasks have no order

Serial queues start asynchronous tasks sequentially

  • Asynchrony in main thread

NSOperation:

chart

NSOperation and NSOperationQueue are specific steps for implementing multithreading

  1. Encapsulate the operations to be performed into an NSOperation object
  2. The NSOperation object is then added to the NSOperationQueue
  3. The system will automatically fetch the NSOperation from the NSOperationQueue
  4. The removed NSOperation encapsulated operations are executed in a new thread

NSOperation queue

The collection class that holds NSOperation. (1) used to store the NSOperation object queue, which can be used to perform some operation (2) general asynchronous request can be used in the network, such as time-consuming operation: operation and operation queue, basic can be seen as in Java thread and the concept of a thread pool. For ios multi-threaded development issues. One point mentioned in some online materials is that although it is a queue, it does not have the concept of a queue, and the operation is not strictly advanced. Afunc is added to the queue and Bfunc is added to the queue. It is inevitable that Afunc will execute this first, but Bfunc will wait for Afunc to complete the operation before B starts and executes. So the concept of queues is a bit of a violation of the concept of multithreading. But on second thought, you can actually refer to the bank’s ticket collection and station system. Therefore, if A queued before B to get the ticket but B finished the operation first, we can also think of it as A queue. But then I saw a bunch of articles on the topic of queue operations, and there was a sentence that said, “Because the time interval between two operations is so close, the thread in the thread pool, who starts first is variable.” Queue queue queue queue queue queue queue queue queue queue queue queue queue queue queue

Commonly used method

  • Subclasses of NSOperation There are three ways to use subclasses of NSOperation:
    1. NSInvocationOperation
    2. NSBlockOperation
    3. Custom subclasses inherit NSOperation to implement the corresponding methods internally
    • NSInvocationOperation
      • Create the NSInvocationOperation object

        - (id)initWithTarget:(id)target selector:(SEL)sel object:(id)arg;
      • Call the start method to start the operation- (void)start;Once the operation is performed, target’s sel method is called
      • Note that by default, when you call the start method you don’t start a new thread to perform the operation, you do it synchronously in the current thread and only asynchronously when you put the NSOperation into an NSOperationQueue
    • NSBlockOperation
      • Create the NSBlockOperation object+ (id)blockOperationWithBlock:(void (^)(void))block;
      • Add more operations via the addExecutionBlock: method- (void)addExecutionBlock:(void (^)(void))block;
      • Note: As long as the operand encapsulated by NSBlockOperation is greater than 1, the operation is executed asynchronously
    • NSOperationQueue
      • What NSOperationQueue does is NSOperation can call the start method to execute the task, but it’s synchronous by default if YOU add NSOperation to the NSOperationQueue, The system automatically performs operations in NSOperation asynchronously
      • Added to theThe master queueAll operations performed by the child thread are placed in:[[NSOperationQueue alloc] init];

        Added to theThe home side columnThe main thread executes all operations in:[NSOperationQueue mainQueue];
      • Add an operation to the NSOperationQueue

        - (void)addOperation:(NSOperation *)op;

        - (void)addOperationWithBlock:(void (^)(void))block;
  • Maximum concurrency

    Related methods for maximum concurrency

    - (NSInteger)maxConcurrentOperationCount;

    - (void)setMaxConcurrentOperationCount:(NSInteger)cnt;
  • Queue cancellation, suspension, and resumption
    • Unqueue all operations

      - (void)cancelAllOperations;

      Tip: You can also call the – (void)cancel method of NSOperation to cancel a single operation
    • Pause and resume queues

      - (void)setSuspended:(BOOL)b;// YES stands for pause queue, NO stands for resume queue

      - (BOOL)isSuspended;
  • Add the dependent
NSOperationQueue *queue = [[NSOperationQueue alloc] init]; NSOperation *a = [NSBlockOperation blockOperationWithBlock:^{NSLog(@"operationA-- ");}]; NSOperation *b = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"operationB---"); }]; NSOperation *c = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"operationC---"); }]; // addDependency [c addDependency:a]; [c addDependency:b]; [queue addOperation:a]; [queue addOperation:b]; [queue addOperation:c];Copy the code
  • You can create dependencies between NSOperations of different queues
  • Note: do not depend on each other, for example, A depends on B, B depends on A
  • Operation priority
    • By setting the priority of NSOperation in the queue, you can change the execution priority of the operation

      - (NSOperationQueuePriority)queuePriority;

      - (void)setQueuePriority:(NSOperationQueuePriority)p;
    • Priority value

      NSOperationQueuePriorityVeryLow = -8L,

      NSOperationQueuePriorityLow = -4L,

      NSOperationQueuePriorityNormal = 0,

      NSOperationQueuePriorityHigh = 4,

      NSOperationQueuePriorityVeryHigh = 8
  • Operation listening

    You can listen to the completion of an operation

    - (void (^)(void))completionBlock;

    - (void)setCompletionBlock:(void (^)(void))block;

Custom NSOperation

  1. The steps for customizing NSOperation are simple to override the – (void)main method to implement the desired task inside
  2. Override – (void)main creates its own auto-release pool (because the main’s auto-release pool cannot be accessed if the operation is asynchronous) and often responds to cancellation by detecting whether the operation has been cancelled with the – (BOOL)isCancelled method

4. Multithreading -NSThread

chart

How a thread is created

1 - (void)createThread1 {NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(download:) object:@"http://a.png"]; Thread. name = @" download thread "; // Start the thread (call self's download method) [thread start]; 1 - (void)createThread2 {[NSThread detachNewThreadSelector:@selector(download: toTarget:self) withObject:@"http://b.jpg"]; } // createThread3 - (void)createThread3 { Execute // [self performSelector:@selector(Download: withObject:@"http://c.gif"]; // [self download:@"http://c.gif"]; [self performSelectorInBackground:@selector(download:) withObject:@"http://c.gif"]; }Copy the code

Advantages and disadvantages of the second and third thread creation methods: Simple and quick disadvantages: you cannot set the thread in more detail

Thread safety

-(void)threadSafe { self.leftTicketCount = 50; self.thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil]; Self.thread1. name = @" window 1 "; self.thread2 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil]; Self.thread2. name = @" window 2 "; self.thread3 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil]; Self.thread3. name = @" thread3 "; [self threadSafeStart]; } - (void)threadSafeStart { [self.thread1 start]; [self.thread2 start]; [self.thread3 start]; } // saleTicket {(void)saleTicket {while (1) {@synchronized(self) {// synchronized(self) int count = self.leftTicketCount; If (count > 0) {[NSThread sleepForTimeInterval: 0.05]; self.leftTicketCount = count - 1; NSLog(@"%@ sold one ticket, remaining %d tickets ", [NSThread currentThread].name, self.leftticketCount); } else { return; // Exit loop}} // unlock}}Copy the code

Commonly used method

  • Scheduling priority of a thread

    + (double)threadPriority;

    + (BOOL)setThreadPriority:(double)p;

    - (double)threadPriority;

    - (BOOL)setThreadPriority:(double)p;

    The value of the scheduling priority ranges from 0.0 to 1.0. The default value is 0.5. A larger value indicates a higher priority
  • Thread name

    - (void)setName:(NSString *)n;

    - (NSString *)name;
  • The main thread
    + (NSThread)mainThread; - (BOOL)isMainThread; + (BOOL)isMainThread;Copy the code
  • Control thread state
    // Start thread // Enter ready state -> run state. - (void)start; + (void)sleepUntilDate:(NSDate *)date; + (void)sleepForTimeInterval:(NSTimeInterval)ti; // Force the thread to stop // enter the death state + (void)exit;Copy the code

    Note: Once a thread has stopped (died), the task cannot be started again

  • Interthread communication
    • What is inter-thread communication? In a process, threads do not exist in isolation. Multiple threads need to communicate frequently
    • Communication between threads: a thread transfers data to another thread. After performing a specific task in one thread, the thread transfers to another thread to continue performing the task
    • Common methods of communication between threads

      - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;

      - (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait;
    • Example: Image download

Fifth, thread safety

  • Multithreading security risks
    • Resource sharing A resource may be shared by multiple threads. That is, multiple threads may access the same resource. For example, multiple threads may access the same object, variable, or file

    • When multiple threads access the same resource, data corruption and data security issues can easily occur

    • Security risk analysis

    • Security risks resolved – Mutual exclusion

    • The mutex

      1. Mutex uses format

      @synchronized {// synchronized} note: only one lock is used to lock one piece of code. Multiple locks do not work

      • Lock as little code as possible
      • Lock the scope of the code, allowing only one thread at a time
      • Mutex argument, any inheriting NSObject * object will do
      • To ensure that the lock is accessible to all threads, all threads are accessing the same lock object
      1. Advantages and disadvantages of mutex Advantages of mutex: It effectively prevents data security problems caused by multi-threading resource grabbing Disadvantages: It consumes a large amount of CPU resources
      2. A mutex can be used only when multiple threads attempt to seize the same resource
      3. Thread synchronization Thread synchronization means that multiple threads execute (perform tasks sequentially) on the same line

Mutex is a thread synchronization technique

  • Spinlocks and mutex have something in common: they both lock a piece of code. At the same time, only the thread can execute the locked code. Differences: When a mutex is locked, other threads sleep, wait for conditions to be met, and then wake up. When a spin lock is locked, other threads do an infinite loop, waiting for the condition to be met, and then execute it immediately, eliminating a wake up process.

  • Nonatomic: Nonatomic: does not lock setter methods. Atomic: Does not lock setter methods. Thread safe, consumes a lot of resources nonatomic: Not thread safe, suitable for mobile devices with small memory

    IOS Development Tips

    All attributes are declared as nonatomic and try to avoid multiple threads snatching the same resource. Try to hand over the business logic of locking and resource snatching to the server side to reduce the pressure on mobile clients

  • The concept of thread safety is to ensure the accuracy of resource information when multiple threads are executing simultaneously.

    1. UI thread — the main thread, most of the classes in UIKit, are not thread-safe
    2. How do you solve this thread insecurity problem in iOS? Apple’s convention is that all UI updates are done in the main thread, so you don’t have multiple threads changing a resource at the same time.
    3. What’s so good about updating the UI in the main thread?
      • Only when the UI is updated in the main thread can multiple threads change the same UI control at the same time
      • The main thread has the highest priority. This means that UI updates are a high priority. Will let the user feel very smooth.
  • Multi-thread security how to control:

    1. The UI is accessed only on the main thread refresh
    2. To prevent resource snatching, use synchronized for locking protection
    3. If asynchronous operations need to be thread safe, use GCD (some functions are safe by default)
  • @synchronized

The purpose of @synchronized is to create a mutex so that no other thread can modify the self object. This is a locking token in Objective-C that prevents the self object from being accessed by another thread at the same time. It is usually used with public variables, such as singleton mode or static variables of an action class.

  • NSLock

From the micro point of view of a thread on the CPU stop-and-go, its running state can be divided into three (classic) : running state, ready state, blocked. Since memory is much slower than CPU speed, the CPU is usually designed not to run directly on the data in memory. To calculate the data in memory, one CPU instruction usually reads the data into the CPU, another CPU instruction performs the operation on the data in the CPU, and finally another CPU instruction writes the result back to memory. I++ read data operation write data because the CPU can be interrupted in the middle of executing two instructions, it may cause another thread that accesses the same memory to run, resulting in error results. If the lock has already been locked by another thread, the current thread blocks until the lock is unlocked by another thread. Unlock the lock. If another thread is blocking because it is waiting for the lock, make that thread ready. Lock the shared data first

  • NSCondition

Thread synchronization has A classic producer-consumer problem: for example, thread A is responsible for downloading data, thread B is responsible for processing data, and thread C is responsible for displaying data. The solution is to use NSCondition: Lock wait signal: Unlock consumer thread (a thread that processes or uses data) : unlock consumer thread (a thread that processes or uses data) Unlock NSCondition has a problem: unlock NSCondition has a problem: A false wake (wait may return when no thread has signaled it) is usually solved with a state variable

  • An immutable object, usually thread-safe

Thread-safe classes and functions: NSArray, NSData, NSNumber….. Non-thread-safe: NSBundle, NSCoder, NSArchiver, NSMutableArray

  • List several synchronization mechanisms for processes and compare their advantages and disadvantages.

Answer: atomic manipulation, semaphore mechanisms, spinlocks, tube paths, convergations, distributed systems

6. Multi-threaded interview questions:

  • Back to the main thread
Dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{UIImage *image = nil; Dispatch_async (dispatch_get_main_queue(), ^{// return to main thread}); // [self performSelector:@selector(settingImage:) onThread:[NSThread mainThread] withObject:image waitUntilDone:YES modes:nil]; // [self performSelectorOnMainThread:@selector(settingImage:) withObject:image waitUntilDone:YES]; });Copy the code

  • Timer for child thread:

The original purpose of the code snippet was to print Hello World after an asynchronous delay of 0.3 seconds. But when it runs, it doesn’t print Hello World. The reason is that NSRunLoop for the non-main thread is not enabled by default, – (void)performSelector (SEL)aSelector withObject (nullable ID)anArgument afterDelay (NSTimeInterval)delay; The function is internally implemented by NSTimer timer. If NSRunLoop is not enabled, NSTimer will not run normally.

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{[self performSelector:@selector(fireBlock: withObject:^{NSLog(@" Hello world");} afterDelay:0.3]; });Copy the code
  • Execute code in the main thread
[self performSelectorOnMainThread: withObject: waitUntilDone:];
[self performSelector: onThread:[NSThread mainThread] withObject: waitUntilDone:];
dispatch_async(dispatch_get_main_queue(), ^{
});
Copy the code
  • Delay to perform
Double delayInSeconds = 2.0; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ }); [self performSelector: withObject: afterDelay:]; [NSTimer scheduledTimerWithTimeInterval: target: selector: userInfo: repeats:];Copy the code
  • How does communist CD work?

The global queue asynchronous operation, will create multiple child threads, the operation is disorderly execution, if there are other tasks before the queue, will wait for other tasks to complete the execution before invoking. Global queue synchronous operation, no new thread, sequential execution; All operations in the main queue are executed sequentially by the main thread. There is no concept of asynchro. Synchronous operations added to the main queue will never be executed and will be deadlocked. The synchronization operation added to the serial queue is deadlocked, but the code before the nested synchronization operation is executed; Synchronized operations added to parallel queues do not deadlock on the main thread; Synchronization operations added to global queues are not deadlocked; The main purpose of synchronization operation is to block the execution of parallel queue tasks. After the current synchronization task is completed, subsequent tasks can be executed. Application: User login.

  • Learn multi-threading, first understand the phone has several important chips: main chip: CPU (dual-core) +GPU (equivalent to the computer graphics card) Memory (RAM) : equivalent to the memory of the computer flash chip: similar to the computer’s hard disk power management chip Bluetooth, wifi, GPS chip

  • Multi-threaded applications: time-consuming operations (database read, image processing (filter)) process is to help you allocate memory multi-threaded open threads generally less than five

  • A way for processes to communicate with each other

Answer: Shared storage system messaging system pipeline: based on the file system

  • Cause of process deadlock

Answer: resource competition and process advance order illegal

  • Four necessary conditions for deadlocks

Answer: mutual exclusion, request hold, inalienable, loop

  • Deadlock handling

Answer: Ostrich strategy, prevention strategy, avoid strategy, detect and unlock deadlock

  • Download the pictures

Vii. Concept:

Queue concept

  • Main thread Each application has only one main thread. All UI updates must be performed on the main thread! The main thread is always working, and it never ends unless the program is killed!

  • The difference between a queue and a thread: A queue is a thread pool that manages when a thread executes.

  • Queues are divided into serial queues and parallel queues: Serial queues: the threads in the queue execute sequentially (not simultaneously). Parallel queues: The threads in the queue execute concurrently. It is important to note that once the task is completed, it does not necessarily exit the queue. You can exit the queue only after the previous task is executed. That is, you can exit the queue only after the previous task is executed.

  • The difference between the main thread and the worker thread is as follows: The main thread is automatically created by the system and can directly operate the UI. Time-consuming operations cannot be performed. The RunLoop is automatically run

  • The main queue differs from the queue created by GCD:

Main thread queue: Synchronization cannot be enabled on the main thread queue, which blocks the main thread. Only asynchronous tasks can be started. Enabling asynchronous tasks does not start new threads, but lowers the priority of asynchronous tasks and allows them to be invoked only when the CPU is free. A synchronization task, on the other hand, preempts resources from the main thread and causes a deadlock. Queues created in the GCD: queues created in the GCD have a lower priority than the main queue, so serial queue start synchronization tasks in the GCD without nested tasks will not block the main thread, only one possible way to cause deadlock, is serial queue, nested start tasks, may cause deadlock.

  • The difference between synchronous and asynchronous:

The synchronization task has a high priority and is executed in sequence in the thread. No new thread is started. Asynchronous tasks have a low priority and are executed out of order in the thread, depending on whether the CPU is available. No new threads are started in the main queue; new threads are started in other queues.

Process and thread concepts:

  • processBaidu encyclopedia

    Process is a running activity of a program on a data set in a computer. It is the basic unit of resource allocation and scheduling in the system and the basis of operating system structure. In the early process-oriented computer architecture, the process is the basic execution entity of the program. In modern thread-oriented computer architectures, processes are containers for threads. A program is a description of instructions, data and their organizational form, while a process is an entity of the program.

  • threadBaidu encyclopedia

    Threads, sometimes called Lightweight processes (LWP), are the smallest unit of a program’s execution flow. A standard thread consists of the thread ID, current instruction pointer (PC), register set, and stack. In addition, thread is an entity in the process, is the system independent scheduling and dispatching of the basic unit, thread does not own system resources, only have a little in the operation of the essential resources, but it can be a process and other threads share all the resources. One thread can create and undo another thread, and multiple threads in the same process can execute concurrently. Because of the mutual restriction between threads, threads appear discontinuity in operation. Threads also have three basic states: ready, blocked, and running. Ready state refers to the thread has all the conditions to run, logically can run, waiting for the processor; The running state is when the thread owns the processor and is running; A blocked state is when a thread is waiting for an event (such as a semaphore) that cannot be logically executed. Every program has at least one thread. If the program has only one thread, that’s the program itself.

A thread is a single sequence control flow in a program. Process has a relatively independent, schedulable execution unit, is the system independent scheduling and dispatching CPU basic unit instruction run program scheduling unit. The simultaneous running of multiple threads in a single program to accomplish different tasks is called multithreading.

  • Summarize the process of

    1. Processes are in the systemThe runningAn application for
    2. Between each process isindependentEach process runs in its own dedicated and protected memory space
  • Thread summary

    1. For a process to execute a task,Must beThere must be threads (Each process must have at least one thread)
    2. A thread is the basic execution unit of a processAll tasks of a process are executed in the thread

    A process is an area of memory that contains some resources. The operating system uses processes to divide its work into functional units. One or more execution units contained in a process are called threads. A process also has a private virtual address space that is accessible only by the threads it contains. Typically, there can be several threads in a process that can take advantage of the resources owned by the process. In operating systems that introduce threads, it is common to regard processes as the basic unit of resource allocation, and threads as the basic unit of independent operation and independent scheduling. Because threads are smaller than processes, they basically do not have system resources, so the cost of scheduling it will be much smaller, and can more efficiently improve the degree of concurrent execution between multiple programs in the system. In short, a program has at least one process, and a process has at least one thread. A program is a process, and multiple tasks in a program are called threads. A thread can only belong to a process and it can only access resources owned by that process. When the operating system creates a process, the process automatically applies for a thread named primary thread or primary thread. An application is composed of one or more processes that work together. In addition, the process has an independent memory unit during execution, while multiple threads share the memory, thus greatly improving the efficiency of the program. Threads are different from processes in their execution. Each independent thread has an entry point for program execution, a sequential execution sequence, and an exit point for the program. However, threads cannot execute independently and must depend on the application, which provides multiple thread execution control. From a logical point of view, the meaning of multithreading is that multiple parts of an application can be executed simultaneously. However, the operating system does not treat multiple threads as multiple independent applications to achieve process scheduling and management and resource allocation. This is an important difference between a process and a thread. Process is a program with a certain independent function on a data set of a running activity, process is a system for resource allocation and scheduling an independent unit. A thread is an entity of a process. It is the basic unit of CPU scheduling and dispatch. It is a smaller unit that can run independently. A thread has virtually no system resources of its own, only a few resources that are essential to running (such as a program counter, a set of registers, and a stack), but it can share all the resources owned by a process with other threads that belong to the same process.

  • Serial 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, a thread can only execute one task at a time.

  • Thread versus process?

    1. Scheduling: Thread as the basic unit of scheduling and allocation, process as the basic unit of owning resources
    2. Concurrency: Concurrent execution can occur not only between processes, but also between multiple threads of the same process
    3. Owning resources: A process is a separate unit that owns resources. Threads do not own system resources, but can access resources belonging to the process
    4. System overhead: When a process is switched (created or canceled), the system allocates and reclaims resources for it, resulting in a significantly higher system overhead than when a thread is created or canceled, which is less efficient. For concurrent operations that require simultaneous and shared variables, only threads can be used, not processes
    5. Processes have their own independent address space. A process crash in protected mode does not affect other processes. Threads have their own heap, local variables, but there is no separate address space between threads, the death of a thread is equal to the death of the whole process, so multi-process procedures than multithreaded procedures robust
    6. A thread is a unit of execution within a process and a schedulable entity within a process. It can share data with other threads in the same process, but has its own stack space

    In short, a program has at least one process, and a process has at least one thread (the main thread). A program is a process, and multiple tasks in a program are called threads.