Detailed explanation of iOS multithreading GCD problem

  • 2021-07-09 09:23:42
  • OfStack

Of all the iOS solutions for multithreading, GCD should be the most attractive, because GCD itself is Apple's solution for multi-core parallel computing. The GCD works automatically with more processor cores to take full advantage of more powerful machines. GCD is short for Grand Central Dispatch and is based on the C language. If you use GCD, the system manages threads entirely, so you don't need to write thread code. Simply define the task you want to perform and add it to the appropriate scheduling queue (dispatch queue). GCD will be responsible for creating threads and scheduling your tasks, and the system will provide thread management directly

dispatch queue is divided into the following three types:

1) Main queue running on the main thread, obtained through dispatch_get_main_queue.


/*!
* @function dispatch_get_main_queue
*
* @abstract
* Returns the default queue that is bound to the main thread.
*
* @discussion
* In order to invoke blocks submitted to the main queue, the application must
* call dispatch_main(), NSApplicationMain(), or use a CFRunLoop on the main
* thread.
*
* @result
* Returns the main queue. This queue is created automatically on behalf of
* the main thread before main() is called.
*/
__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0)
DISPATCH_EXPORT struct dispatch_queue_s _dispatch_main_q;
#define dispatch_get_main_queue() \
DISPATCH_GLOBAL_OBJECT(dispatch_queue_t, _dispatch_main_q)

It can be seen that dispatch_get_main_queue is also a kind of dispatch_queue_t.

2) The parallel queue global dispatch queue is obtained by dispatch_get_global_queue, and three dispatch queue with different priorities are created by the system. The execution order of the parallel queue is the same as the order in which it joins the queue.

3) Serial Queue serial queues1 is used for sequential synchronous access, and can create any number of serial queues, each of which is concurrent.

Serial queues are useful when you want tasks to be executed in a specific order. Serial queues perform only one task at the same time. We can use serial queues instead of locks to protect shared data. Unlike locks, a serial queue ensures that tasks are executed in a predictable order.

serial queues is created by dispatch_queue_create, and the functions dispatch_retain and dispatch_release can be used to increase or decrease the reference count.

Usage of GCD:


//  Background execution: 
 dispatch_async(dispatch_get_global_queue(0, 0), ^{
   // something
 });

 //  The main thread executes: 
 dispatch_async(dispatch_get_main_queue(), ^{
   // something
 });

 // 1 Secondary execution: 
 static dispatch_once_t onceToken;
 dispatch_once(&onceToken, ^{
   // code to be executed once
 });

 //  Delay 2 Execution in seconds: 
 double delayInSeconds = 2.0;
 dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
 dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
   // code to be executed on the main queue after delay
 });

 //  Customize dispatch_queue_t
 dispatch_queue_t urls_queue = dispatch_queue_create("blog.devtang.com", NULL);
 dispatch_async(urls_queue, ^{ 
       // your code 
 });
 dispatch_release(urls_queue);

 //  Consolidate summary results 
 dispatch_group_t group = dispatch_group_create();
 dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{
   //  Threads executing in parallel 1
 });
 dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{
   //  Threads executing in parallel 2
 });
 dispatch_group_notify(group, dispatch_get_global_queue(0,0), ^{
   //  Summary results 
 });

An example of applying GCD:


 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSURL * url = [NSURL URLWithString:@"http://www.baidu.com"];
    NSError * error;
    NSString * data = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&error];
    if (data != nil) {
      dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"call back, the data is: %@", data);
      });
    } else {
      NSLog(@"error when download:%@", error);
    }
  });

Another use of GCD is that it allows programs to run in the background for a long time.

When not using GCD, app is exited by pressing home, app only has a maximum of 5 seconds to do some saving or cleaning of resources. However, after using GCD, app has a maximum of 10 minutes to run in the background for a long time. This time can be used to clean up the local cache, send statistics and so on.

The example code for making the program run in the background for a long time is as follows:


// AppDelegate.h Documents 
@property (assign, nonatomic) UIBackgroundTaskIdentifier backgroundUpdateTask;

// AppDelegate.m Documents 
- (void)applicationDidEnterBackground:(UIApplication *)application
{
  [self beingBackgroundUpdateTask];
  //  Add the code you need to run for a long time here 
  [self endBackgroundUpdateTask];
}

- (void)beingBackgroundUpdateTask
{
  self.backgroundUpdateTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
    [self endBackgroundUpdateTask];
  }];
}

- (void)endBackgroundUpdateTask
{
  [[UIApplication sharedApplication] endBackgroundTask: self.backgroundUpdateTask];
  self.backgroundUpdateTask = UIBackgroundTaskInvalid;
}


Related articles: