Introduction to the

NSOperation and NSOperationQueue are a set of multi-threaded solutions provided by Apple. They are based on a higher level of ENCAPSULATION of GCD and are fully object-oriented. But it is easier to use and more readable than GCD.

  • Benefits:

You can add a completed code block, complete, to execute after the action is complete. Add dependencies between operations to control the order of execution. Set the priority of the operation. You can cancel the execution of an operation. Use KVO to observe the execution status: isExecuteing, isFinished, isCancelled.

There are similar concepts of “task” and “queue” in NSOperation and NSOperationQueue.

1.NSOperation

Task, or operation. That is, the piece of code that you execute in the thread. NSOperation is an abstract class that encapsulates tasks using subclasses NSInvocationOperation, NSBlockOperation, or a custom subclass.

2.NSOperationQueue

Refers to the queue used to store operations.

  • Queue type

Main queue and custom queue. The main queue runs on top of the main thread, while custom queues execute in the background.

  • Task status and order

Different from the queue FIFO (first in, first out) principle in GCD. For tasks added to the NSOperationQueue, the ready state is first entered (the ready state depends on the dependencies between tasks), and then the order in which the ready tasks start execution (rather than finish execution) is determined by the relative priority of the tasks.

  • Concurrent and serial

Task queue by setting the maximum number of concurrent operation maxConcurrentOperationCount to control concurrency, serial.

3. NSOperation implements multi-threading

By default, when NSOperation is used alone, the system performs operations synchronously. Asynchronous execution is better achieved with NSOperationQueue.

  • The procedure is divided into three steps

Create a task: Encapsulate the task to be executed into an NSOperation object. Create a queue: the NSOperationQueue object. Add the task to the queue: Add the NSOperation object to the NSOperationQueue object.

The system automatically pulls the NSOperation out of the NSOperationQueue and executes the operation in the new thread.

3.1 Creating an NSOperation Task

NSOperation is an abstract class and cannot be used directly to encapsulate tasks. Subclasses are used to encapsulate tasks: NSInvocationOperation, NSBlockOperation, and custom subclasses.

NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(task1) object:nil]; [op start]; // Start executingCopy the code
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
        //  do some thing...
}]; 
[op start];
Copy the code

In addition, you can add additional tasks to a task object.

NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ // do something... }]; // Add additional operation [op addExecutionBlock:^{// do otherthing...}];Copy the code
  • In no use NSOperationQueue, used alone in the main threadNSOperationA subclass object executes a task that is executed in the current thread and does not start a new thread.
  • Use a subclassNSBlockOperationAnd calls the methodaddExecutionBlock: If the number of operations added is large, a new thread will be automatically started.
2. Create an NSOperationQueue queue

There are two types: main queue and custom queue.

  • The home side column
NSOperationQueue *queue = [NSOperationQueue mainQueue];
Copy the code

Any operations added to the main queue are executed in the main thread.

  • Custom queue

Operations added to this queue are automatically placed in child threads for execution; It also contains serial and concurrent functions.

NSOperationQueue *queue = [[NSOperationQueue alloc] init];

queue. maxConcurrentOperationCount = 3;
Copy the code

Can set properties maxConcurrentOperationCount maximum number of concurrent operation, decided to serial and concurrent.

Attribute maxConcurrentOperationCount

= 1; // Serial queue, tasks can only be executed sequentially = 2; // Concurrent queue, >2, the task is executed concurrently, can execute multiple operations at the same time = 8; Of course, this value should not exceed the system limit, even if a large value is set, the system will automatically adjust to min.

3. Add the operation to the queue

Method addOperation:

    NSOperationQueue *queue = [[NSOperationQueue alloc] init];

    NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(task1) object:nil];
 
    NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
        //.....
    }];
    [op3 addExecutionBlock:^{
        //.....
    }];

    [queue addOperation:op1];  
    [queue addOperation:op3];  
Copy the code

Method addOperationWithBlock:

NSOperationQueue *queue = [[NSOperationQueue alloc] init]; [queue addOperationWithBlock:^{//.....}];Copy the code

Operations and operation queues, usage steps and basic usage methods, control serial/concurrent execution,

  • Adding a task to the queue is equivalent to calling the start method of the task

NSOperation rely on

Dependencies make it easy to control the order in which tasks are executed.

addDependency:(NSOperation *)op; Add the dependent

removeDependency:(NSOperation *)op; Remove dependencies NSArray

*dependencies; An array of task objects that are completed before the current task begins execution

NSOperationQueue *queue = [[NSOperationQueue alloc] init]; NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{ //..... }]; NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{ //..... }]; // addDependency [op2 addDependency:op1]; // make op2 dependent on op1. Op1 [queue addOperation:op1] is executed. [queue addOperation:op2];Copy the code
  • State of readiness

When all dependencies for a task have been completed, task objects typically enter a ready state, waiting to execute.

NSOperation provides the priority attribute queuePriority. By default, all the operation of the newly created object is NSOperationQueuePriorityNormal priority. However, you can change the priority of tasks in the same queue by using the setQueuePriority: method.

The queuePriority attribute applies to tasks in the same queue, not to tasks in different queues.

Priority values: NSOperationQueuePriorityVeryLow = -8L, NSOperationQueuePriorityLow = -4L, NSOperationQueuePriorityNormal = 0, (the default) NSOperationQueuePriorityHigh = 4, NSOperationQueuePriorityVeryHigh = 8

Priorities and dependencies

  • Priority attributequeuePriority Determines between tasks that enter the ready stateStart execution order. And priorities are no substitute for dependencies.
  • If a queue contains both high-priority and low-priority tasks, and both tasks are ready, the queue executes the high-priority task first.
  • Priorities are no substitute for dependencies.

If A queue contains both ready task A and unready task B, B has A higher priority than A. So, B takes precedence. If you want to control the startup sequence between operations, you must use dependencies.

Communication between threads

After processing sub-trip tasks, return to main trip processing

NSOperationQueue *queue = [[NSOperationQueue alloc]init]; [queue addOperationWithBlock:^{//..... [[NSOperationQueue mainQueue] addOperationWithBlock:^{// Back to main thread, Do some UI refreshes and so on}];}];Copy the code

Cancel the thread

An ongoing operation cannot be canceled. You can cancel only unperformed operations.

1. You can cancel an unperformed operation by using the Cancel method.

NSOperationQueue *queue1 = [[NSOperationQueue alloc]init];
NSBlockOperation *block1 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"block11");
}];
NSBlockOperation *block2 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"block22");
}];
NSBlockOperation *block3 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"block33");
}];
[block3 cancel];

[queue1 addOperations:@[block1,block2,block3] waitUntilFinished:YES];
Copy the code
  1. CancelAllOperations method, but cannot remove the operation being performed.
Queue1 cancelAllOperations [queue1 cancelAllOperations];Copy the code

3. Suspend the queue, so that the queue task is no longer executed, but the ongoing operation cannot be suspended.

queue1.suspended = YES;
Copy the code

To cancel an ongoing operation, you can customize NSOperation, which intercepts the main method.

1. When any operation is executed, the start method is called first, which updates the state filtering operation of the operation (such as filtering out operations in the “cancel” state) 2. After filtering through the start method, the main method is called only for normally executable operations. 3. Override the entry method (main) of the operation to specify the task performed by the operation. 4. The main method is executed asynchronously on child threads by default.

Thread synchronization and thread safety

  • Thread safety

Multiple threads may run a piece of code simultaneously. If the result of each run is the same as the result of a single thread run, and the values of the other variables are the same as expected, it is thread-safe. If only reads (no writes) are performed on a global or static variable per thread, the variable is generally thread-safe. If multiple threads are writing simultaneously (changing the value of a variable), thread synchronization needs to be considered, or thread safety may be compromised.

  • Thread synchronization

It can be understood as thread A and thread B work together. When thread A reaches A certain level, it depends on A certain result of thread B, so it stops and signals B to run. B does what he says and gives the result to A; A Continue operations. Example: train ticket sales

Thread-safe solution: lock

Threads can be locked so that while one thread is performing the operation, other threads are not allowed to perform the operation.

IOS implements thread locking in a number of ways:

Dispatch_semaphore: recommended. Good performance NSLock @synchronized: worst performance OS_UNfair_lock: IOS10 start NSCondition NSConditionLock pthread_mute OSSpinLock: iOS10 discard atomic(property) set/get: atomic operation

Idea: Lock before write operation, unlock after write operation.

The spin lock.

Be busy, etc. Busy means that when a locked resource is accessed, the caller thread does not sleep, but loops there until the locked resource releases the lock. This applies to scenarios where threads are expected to wait for a lock for a very short time. Locking code (critical sections) is often called, but contention rarely occurs. CPU resources are not tight, multi-core processors

Exclusive locks:

Will sleep. Sleep means that when a locked resource is accessed, the caller thread will sleep and the CPU can schedule other threads to work. Until the locked resource releases the lock. The dormant thread is awakened. It is expected that threads wait for locks for a long time. Critical area Fierce competition critical area I/O operations Critical area Complex code or large number of loops single-core processor

Deadlock:

A deadlock occurs when two operations wait for each other to complete, causing an infinite loop in which neither operation can be performed.

Summary of common attributes and methods

.

NSOperation vs. GCD

  • NSOperation is a high abstraction of threads, and when used in a project, the program structure of the project will be better. The design idea of subclassing NSOperation is to have the advantages of object oriented (reuse, encapsulation), making the implementation is multithreaded support, and the interface is simple.

Recommended for complex projects.

  • GCD itself is very simple, easy to use, for uncomplicated multi-threaded operation, will save code, and the use of Block parameters, will be more readable code.

Recommended for simple projects.

  • The advantages of the NSOperation

1.NSOperationQueue makes it easy to set up dependencies between operations that GCD requires a lot of code to implement. 2. NSOperation can easily adjust the execution sequence and set the maximum number of concurrent requests. NSOperationQueue supports KVO, which monitors whether operation isExecuted, isFinished, or canceled. 4.GCD supports only FIFO queue columns