iOS multithreaded programming--talking about GCD

Source: Internet
Author: User
Tags semaphore

GCD for iOS developers, he and Nsthread,nsoperation as the main iOS development in the three multi-threaded implementation method, and GCD is the most basic, so for as a ioser,gcd must be mastered.

I have basically mastered the basic use of GCD by reading the following two articles. So thank the two authors first.

    • GCD in-depth understanding: the first part
    • The use and multithreading development of iOS Multithreading Development--GCD (II.)
First, the basic concept

For beginners, the most common at the same time is the most easy to confuse the GCD in some of the basic concepts.

  1. Parallel and concurrency (Parallelism && Concurrency)

    • Parallelism: As the name implies simultaneous action, two tasks are processed on two threads (thread) and do not interfere with each other. The root cause is the multi-core processing , which solves the task faster. (can be analogous to two water pipes at the same time to the swimming pool)
    • Concurrency: As the name implies, occurs simultaneously. For some poorly performing machines, such as those with only a single core, in order for the user to feel able to handle multiple tasks at the same time , he needs to implement a "pseudo-parallelism" by constantly switching the threads being processed, thus preventing the user from being able to perform the next task for too long. (Can analogy to I use two to give water to the swimming pool, but because there is only one pipe, and the direction of the discharge of 2 aspects, so need to constantly switch, so that both sides to achieve the required level)
    • Differentiate such as:
  2. Serial and concurrency (Serial && Concurrent)

    • Serial: Because only one task is executed when a thread is executed, each task relies on the first-come-first processing (FIFO) principle to process all the resulting content.
    • Parallel: When a task is received, in parallel, he opens multiple threads, assigning each task to each thread, so that each task can be executed at the same time. This effectively reduces the time spent.
    • The chart is divided as follows:

  3. queue: As mentioned earlier, when you tell a computer what you need to do, the computer will put one thing you tell him in his own team, it is clear that the first thing to tell him in front, and then tell him the things put in the back, that is, FIFO principle to deal with everything , just like in a line.

    • There are 2 main queues in GCD, which are mentioned earlier:
      • Serial queue
      • Concurrent queues
    • There are 5 types of existing queues that Apple provides to us (excluding content that we add ourselves later)
      • Main queue: By default everything is handled under the main queue, and as long as someone with coding experience, the home row is obviously (serial queue).
      • Global Dispatch Queues: By default, the global queue is the collectively known for the system-provided concurrent queues and is divided into the following (priority levels from low to high) depending on the priority of the queue:
        • Background
        • Low
        • Default
        • High
  4. Synchronous vs. Asynchronous (synchronization && asynchronous)
    -Sync: Sync refers to the tasks you need to perform after the original content is completed.
    -Async: Async refers to the simultaneous processing of new tasks at the same time as the original content execution.
Second, basic use

Now that you have learned it, you must use it. So let's start by simulating an environment:
In this program, only the home team, and then you want to download a picture from the Internet, put it in your own mobile phone, and then the user can be on the phone inside the picture for a variety of processing.
But here's the problem: we all know that downloading takes time, and although it's now 4G times, the download is fast, but if the picture is large, it takes a long time to wait. And in this period of time, the user can not do anything, can only silently wait.

It's obviously a bad user experience.

So now that we know where the problem is, we need to find a way to solve it:

    1. We need to add an animated effect when the user waits and tell him we're downloading (this is not about today's topic, we don't go into it)
    2. Put the download task in the background (if it is still in the foreground, even if there is animation, the animation will not move)

Then this is the time for the asynchronous queue to exist.

As mentioned in the basic concepts above, the execution is divided into synchronous execution and asynchronous execution, and the task queue is divided into serial queue and concurrent queue. So they combine one by one with each other, a total of 4 situations exist, and the main combination of the state diagram is as follows:

Single-queue serial queue, synchronous execution

The code is as follows:

func Serialdispatchqueuewithsync () {let  queue = Dispatch_queue_create ( "Serialdispatchqueue" , dispatch_queue_serial) print  ( "0" ) Dispatch_sync (queue) {print  (" 1 ")} dispatch_sync (queue) {print  (" 2 ")} dispatch_sync (queue) {pri NT  ( "3" )} dispatch_sync (queue) {print ( "4" )} dispatch_sync (queue) {print  (  "5" ) } print  ( "6" )} 

The results of the operation are as follows:

0123456
Serial queue, asynchronous execution

The code is as follows:

Func Serialdispatchqueuewithasync () { LetQueue = Dispatch_queue_create ("Serial", dispatch_queue_serial)Print("0") Dispatch_async (queue) {Print("1")} dispatch_async (queue) {Print("2")} dispatch_async (queue) {Print("3")} dispatch_async (queue) {Print("4")} dispatch_async (queue) {Print("5")} dispatch_async (queue) {Print("6")    }Print("7")}

The results of the operation are as follows:

07123456

Explanation: Because the queue is executed asynchronously, called the Dispatch_async function, the output 1 2 3 4 5 6 is in another thread, so it has nothing to do with output 1 7 in the main thread.

Concurrent queues, synchronous execution

The code is as follows:

Func Concurrentdispatchsqueuewithsync () { LetQueue = Dispatch_queue_create ("Concurrent", dispatch_queue_concurrent)Print("0") Dispatch_sync (queue) {Print("1")Print(" A")Print("very")} dispatch_sync (queue) {Print("2")Print("a")Print("All")} dispatch_sync (queue) {Print("3")Print(" the")Print(" the")} dispatch_sync (queue) {Print("4")Print(" A")Print(" the")    }Print("5")}

The results of the operation are as follows:

0112132222333233442435
Concurrent queues, asynchronous execution

The code is as follows:

Func Concurrentdispatchsqueuewithasync () { LetQueue = Dispatch_queue_create ("Concurrent", dispatch_queue_concurrent)Print("0") Dispatch_async (queue) {Print("1")Print(" A")Print("very")} dispatch_async (queue) {Print("2")Print("a")Print("All")} dispatch_async (queue) {Print("3")Print(" the")Print(" the")} dispatch_async (queue) {Print("4")Print(" A")Print(" the")    }Print("5")}

The results of the operation are as follows:

071212322134322354233524353
Other common uses: Suspend and resume
    • Thread Hangs:dispatch_suspnd()
    • Thread Recovery:dispatch_resume()
Signal Volume

Because sometimes (for example, when creating an object to add an array), because different threads manipulate the same object, so it is easy to get an error, this time need to control the corresponding content through the semaphore, when the semaphore is 0 , enter the waiting state, cannot execute the following content When the semaphore is 1 , it can be executed while the signal volume is reduced by one, and after execution, the semaphore is added one.
-Wait for execution dispatch_semaphore_wait()
-Signal volume plus onedispatch_semahore_signal

Execute only once

Sometimes, the creation of something can only be created once (that is, a single case), this time you need to dispatch_once() use
The code is as follows:

var token: dispatch_once_t = 0func test() {    dispatch_once(&token) {        call to test()")    }    println("This is printed for each call to test()")}
How to solve the problem of reading and writing (buying tickets)

Because of the routine coding process that is often encountered when you call this variable. Another thread is calling this variable (only in the concurrency process), and if two threads are reading the data, then there is no problem, but if one is writing, or two is writing, then there is a big problem, so Apple has also prepared a way for us to solve this problem in GCD. , that is dispatch_barrier_async , this method allows the right content to be added to the concurrency process, which facilitates the organization of content modification, so that the corresponding content can only be modified in the current thread.

Frequently asked Questions: deadlock:
letqueue= dispatch_get_main_queue()dispatch_async(queue) {     dispatch_sync(queue, {         print("1")    })}

Production principle: Because it dispatch_sync() will wait until the end of the main thread to continue executing the next code, but dispatch_sync() this method calls the main thread, so lunch until the end of the main thread, so you can not return, will be stuck here.

Explanation: Because it is a concurrent queue, he creates multiple threads so that the tasks of each thread can be completed as soon as possible, so there is some discrepancy in the order.

Finally, we summarize the single queue by two dynamic graphs: dispatch_sync
- (void)viewDidLoad{  [super viewDidLoad];  dispatch_sync0), ^{    NSLog(@"First Log");  });  NSLog(@"Second Log");}

    1. The main queue is in a predetermined order
    2. The viewdidload is executed on the main thread.
    3. Until you execute thedispatch_sync
    4. Call the dispatch_sync code, add the block to the global queue, and the home column hangs.
    5. The global queue first completes the content that was previously stored in the global queue.
    6. After the task is completed, the dispatch_sync contents of the block are executed.
    7. Complete the task in block, the task on the home row is restored
    8. The primary queue continues to perform other tasks.
Dispatch_async
- (void) viewdidload{[  Super Viewdidload]; Dispatch_async (dispatch_  get_global_  queue (Dispatch_queue_  priority_high, 0), ^{ NSLog (@ "First Log  ");  }); NSLog (@ "Second Log");}! [dispatch_sync ] (https://camo.githubusercontent.com/2c7cbaf76001a56622e14cf48a8d914d4b5c9df4/ 687474703a2f2f63646e312e72617977656e6465726c6963682e636f6d2f77702d636f6e74656e742f75706c6f6164732f323031342f30312f6469737 0617463685f6173796e635f696e5f616374696f6e2e676966 )  
    1. The primary queue performs the task sequentially-followed by an instantiated UIViewController task, which contains the viewDidLoad .
    2. viewDidLoadExecutes on the main thread.
    3. The main thread is currently viewDidLoad inside and is about to arrive dispatch_async .
    4. dispatch_async Blockis added to a global queue and will be executed at a later time.
    5. viewDidLoadAfter adding dispatch_async to the global queue, the main thread turns its attention to the remaining tasks. At the same time, the global queue handles its unfinished tasks concurrently. Remember Block that the global queue will be queued in (FIFO) order, but can be executed concurrently.
    6. dispatch_asyncthe code block added to begins execution.
    7. dispatch_async BlockComplete, two NSLog statements put their output on the console.
Dispatch Group

Since we can handle each task, we continue to simulate an environment, when we need to download content on the Internet (the content needs to be linked to normal use), at this time, the above single queue is not enough (or if the use of single-queue effect is not too long, Is that the integrity of the file is not good enough)

At this point we need to introduce multiple queues, and when multiple content is processed, let the system tell us that we have completed the above download. Can continue to do the next thing.

Task start

In GCD, we can notify the dispatch_group_enter beginning of the current task, and corresponding to it, we must manually notify the dispatch group when the task is finished () so that the dispatch_group_leave dispatch group will know that our task is over.

The code is as follows (since there is a photo class in the demo, the OC Code is affixed here):

// 3Photo *photo = [[Photo alloc] initwithURL:url withCompletionBlock:^(UIImageNSError *_error) {    if (_error) {        error = _error;    // 4}];[[PhotoManager sharedManager] addPhoto:photo];
Task reminders

When all of our tasks are manually notified, then we need to use a reminder to tell him (I've finished everything, and then I need to try where I can do it), and there are two types of reminders in GCD:

    • dispatch_group_wait() + dispatch_async()
    • dispatch_group_notify
Other common uses dispatch_apply ()

Sometimes it is necessary to invoke a For loop to execute repeatedly, but when the amount of code to be executed is too large, the for is inefficient and needs to be executed at this time, which is inefficient, dispatch_apply() but less efficient when the amount of code that needs to be executed is relatively low dispatch_apply() .

The effect of this method is the dispatch_sync same, so pay attention to the deadlock (mentioned later)

iOS multithreaded programming--talking about GCD

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.