線程控制:GCD開發(fā)常用總結(jié)梳理

一、相關(guān)概念

GCD全稱Grand Central Dispatch,屬于系統(tǒng)級(jí)的線程管理,通過 GCD,我們可以對(duì)當(dāng)前程序執(zhí)行的線程進(jìn)行調(diào)度與控制,而不需要過度關(guān)注線程創(chuàng)建釋放相關(guān)內(nèi)容,這無疑大大節(jié)約了開發(fā)的精力,并且將繁瑣的線程抽象起來,更有利于掌握和理解;

  • 串行(Serial):讓任務(wù)一個(gè)接著一個(gè)地執(zhí)行(一個(gè)任務(wù)執(zhí)行完畢后,再執(zhí)行下一個(gè)任務(wù))
  • 并發(fā)(Concurrent):可以讓多個(gè)任務(wù)并發(fā)(同時(shí))執(zhí)行(自動(dòng)開啟多個(gè)線程同時(shí)執(zhí)行任務(wù))并發(fā)功能只有在異步(dispatch_async)函數(shù)下才有效。
  • 同步(Synchronous):在當(dāng)前線程中執(zhí)行任務(wù),不具備開啟新線程的能力
  • 異步(Asynchronous):在新的線程中執(zhí)行任務(wù),具備開啟新線程的能力

二、舉例說明

沒有什么比直接使用例子更通俗易懂:

隊(duì)列

分為串行隊(duì)列與并行隊(duì)列,執(zhí)行分為異步與同步

    //串行隊(duì)列的創(chuàng)建方法
    dispatch_queue_t queueSerial = dispatch_queue_create("test.queue", DISPATCH_QUEUE_SERIAL);
    //并發(fā)隊(duì)列的創(chuàng)建方法
    dispatch_queue_t queueC = dispatch_queue_create("conTest.queue", DISPATCH_QUEUE_CONCURRENT);
    NSLog(@"asyncConcurrent---begin");
    //同步執(zhí)行任務(wù)創(chuàng)建方法
    dispatch_sync(queueC, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"1---sync---%@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queueC, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"2---sync---%@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queueC, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"3---sync---%@",[NSThread currentThread]);
        }
    });
    
    //異步執(zhí)行任務(wù)創(chuàng)建方法
    dispatch_async(queueC, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"1------%@",[NSThread currentThread]);
        }
    });
    dispatch_async(queueC, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"2------%@",[NSThread currentThread]);
        }
    });
    dispatch_async(queueC, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"3------%@",[NSThread currentThread]);
        }
    });
    NSLog(@"syncConcurrent---end");
    
    //并發(fā)同步隊(duì)列在一個(gè)線程中執(zhí)行,并發(fā)異步隊(duì)列則由系統(tǒng)分配的線程執(zhí)行,執(zhí)行速度不一定比當(dāng)前線程的速度慢

主線程與線程切換


  dispatch_queue_t queue = dispatch_get_main_queue();
    NSLog(@"asyncMain---begin");
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"1------%@",[NSThread currentThread]);
        }
    });
    dispatch_block_t block = ^{
        NSLog(@"block------%@",[NSThread currentThread]);
        NSLog(@"new block message");
    };
    
    dispatch_async(queue, block);
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"2------%@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"3------%@",[NSThread currentThread]);
        }
    });
    NSLog(@"asyncMain---end");
    //在指定線程中執(zhí)行的異步操作,遵循代碼執(zhí)行順序,碰到異步的函數(shù)塊,即拋到線程最后排隊(duì);

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        dispatch_async( dispatch_get_main_queue(), ^{
            
        });
    });
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            for (int i = 0; i < 2; ++i) {
                NSLog(@"1------%@",[NSThread currentThread]);
            }
            //回到主線程
            dispatch_async(dispatch_get_main_queue(), ^{
                for (int i = 0; i < 2; ++i) {
                    NSLog(@"2------%@",[NSThread currentThread]);
                }
            });
        });

dispatch_once用法

// 使用dispatch_once構(gòu)建單例,可以保證單例線程安全
+ (instancetype)shareInstance {
    static PhotoHandler *handler = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        handler = [[PhotoHandler alloc] init];
    });
    return handler;
}

dispatch_barrier 與dispatch_group 及 dispatch_apply 常用方法及區(qū)別

dispatch_group在日常開發(fā)中用處可能更大一點(diǎn)

 dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //執(zhí)行耗時(shí)操作1
        NSLog(@"執(zhí)行耗時(shí)操作1");
         NSLog(@"執(zhí)行耗時(shí)操作1------%@",[NSThread currentThread]);
        dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            for (long i = 0 ; i < 7000000; i ++) {
                long j = i;
            }
            NSLog(@"內(nèi)部在異步1");
            NSLog(@"內(nèi)部在異步1------%@",[NSThread currentThread]);
        });
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            NSLog(@"內(nèi)部在異步3");
            NSLog(@"內(nèi)部在異步3------%@",[NSThread currentThread]);
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                sleep(1); //這里線程睡眠1秒鐘,模擬異步請求
                NSLog(@"內(nèi)部在異步2");
                NSLog(@"內(nèi)部在異步2------%@",[NSThread currentThread]);
                
            });
        });
        
    });
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //執(zhí)行耗時(shí)操作2
        NSLog(@"執(zhí)行耗時(shí)操作2------%@",[NSThread currentThread]);
        NSLog(@"執(zhí)行耗時(shí)操作2");
    });
    
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //執(zhí)行耗時(shí)操作3
        NSLog(@"執(zhí)行耗時(shí)操作3------%@",[NSThread currentThread]);
        NSLog(@"執(zhí)行耗時(shí)操作3");
    });
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"前面的異步操作已完成");
    });
    
    //dispatch_group_create()可以創(chuàng)建一個(gè)完全的線程控制,這這個(gè)group中的線程,無論該線程是否新開異步線程,
    //dispatch_group_notify都會(huì)在該group線程所有內(nèi)容執(zhí)行完成以后,再執(zhí)行相關(guān)內(nèi)容(但是sleep(1); 模擬異步請求,dispatch_group_notify不會(huì)等待 如果要精確確定異步的執(zhí)行完畢,可以用dispatch_group_enter, dispatch_group_leave來管理)
    //所謂異步執(zhí)行就是將當(dāng)前在異步執(zhí)行的代碼以函數(shù)塊形式排隊(duì)放到線程(系統(tǒng)分配的線程,不一定是目前執(zhí)行的線程)執(zhí)行的最后
    //由于執(zhí)行的線程不一致,所以完成先后順序也不一致
//對(duì)于內(nèi)部再次異步的的內(nèi)容(如網(wǎng)絡(luò)請求),group并不能保證獲取結(jié)果以后再執(zhí)行通知

dispatch_barrier 與dispatch_apply

   //GCD的快速迭代方法
    dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    /*! dispatch_apply函數(shù)說明
           *
           *  @brief  dispatch_apply函數(shù)是dispatch_sync函數(shù)和Dispatch Group的關(guān)聯(lián)API
           *         該函數(shù)按指定的次數(shù)將指定的Block追加到指定的Dispatch Queue中,并等到全部的處理執(zhí)行結(jié)束
           *
           *  @param 6    指定重復(fù)次數(shù)  指定6次
           *  @param queue 追加對(duì)象的Dispatch Queue
           *  @param index 帶有參數(shù)的Block, index的作用是為了按執(zhí)行的順序區(qū)分各個(gè)Block
           *
          */
    
    dispatch_apply(6, globalQueue, ^(size_t index) {
        NSLog(@"%zd---globalQueue---%@",index, [NSThread currentThread]);
    });
    
    dispatch_queue_t queue = dispatch_queue_create("ssss", DISPATCH_QUEUE_CONCURRENT);
    
    
    
   
    
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"1------%@",[NSThread currentThread]);
        }
        
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            NSLog(@"內(nèi)部在異步1");
            NSLog(@"內(nèi)部在異步1------%@",[NSThread currentThread]);
            
        });
    });
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"2------%@",[NSThread currentThread]);
        }
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            NSLog(@"內(nèi)部在異步2");
            NSLog(@"內(nèi)部在異步2------%@",[NSThread currentThread]);
            
        });
        dispatch_async(queue, ^{
            for (int i = 0; i < 2; ++i) {
                NSLog(@"內(nèi)部queue------%@",[NSThread currentThread]);
            }
        });
    });
    //先執(zhí)行完柵欄前面的在執(zhí)行后面的
    dispatch_barrier_sync(queue, ^{
        NSLog(@"----barrier-----%@", [NSThread currentThread]);
    });
    
        /**
         1.柵欄操作時(shí)候,只能攔截該線程中第一層異步操作的內(nèi)容,對(duì)第一層中再次異步操作的線程無法攔截,同時(shí)屬于這個(gè)線程的也不行
         */
    
    
    
//    dispatch_async(queue, ^{
//        for (int i = 0; i < 2; ++i) {
//            NSLog(@"3------%@",[NSThread currentThread]);
//        }
//    });
//    dispatch_async(queue, ^{
//        for (int i = 0; i < 2; ++i) {
//            NSLog(@"4------%@",[NSThread currentThread]);
//        }
//    });
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSLog(@"only once");
    });
    //延時(shí)執(zhí)行,不受柵欄的影響
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"run -----");
    });

死鎖相關(guān)情形

-(void)deadThread {
    NSLog(@"=================4");
    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"=================5");
    });
    NSLog(@"=================6");
}

-(void)deadThread2 {
    dispatch_queue_t queue = dispatch_queue_create("com.demo.serialQueue", DISPATCH_QUEUE_SERIAL);
    NSLog(@"1"); // 任務(wù)1
    dispatch_async(queue, ^{
        NSLog(@"2"); // 任務(wù)2
        dispatch_sync(queue, ^{
            NSLog(@"3"); // 任務(wù)3
        });
        NSLog(@"4"); // 任務(wù)4
    });
    NSLog(@"5"); // 任務(wù)5
/**
 執(zhí)行任務(wù)1;
 遇到異步線程,將【任務(wù)2、同步線程、任務(wù)4】加入串行隊(duì)列中。因?yàn)槭钱惒骄€程,所以在主線程中的任務(wù)5不必等待異步線程中的所有任務(wù)完成;
 因?yàn)槿蝿?wù)5不必等待,所以2和5的輸出順序不能確定;
 任務(wù)2執(zhí)行完以后,遇到同步線程,這時(shí),將任務(wù)3加入串行隊(duì)列;
 又因?yàn)槿蝿?wù)4比任務(wù)3早加入串行隊(duì)列,所以,任務(wù)3要等待任務(wù)4完成以后,才能執(zhí)行。但是任務(wù)3所在的同步線程會(huì)阻塞,所以任務(wù)4必須等任務(wù)3執(zhí)行完以后再執(zhí)行。這就又陷入了無限的等待中,造成死鎖。
 */
}

semaphore信號(hào)量的應(yīng)用

信號(hào)量使用的主要三個(gè)函數(shù)

//創(chuàng)建信號(hào)量,參數(shù):信號(hào)量的初值,如果小于0則會(huì)返回NULL
dispatch_semaphore_create(信號(hào)量值)
 
//等待降低信號(hào)量
dispatch_semaphore_wait(信號(hào)量,等待時(shí)間)
 
//提高信號(hào)量
dispatch_semaphore_signal(信號(hào)量)

其實(shí),這有點(diǎn)類似鎖機(jī)制了,只不過信號(hào)量都是系統(tǒng)幫助我們處理了,我們只需要在執(zhí)行線程之前,設(shè)定一個(gè)信號(hào)量值(這個(gè)值必須是大于或者等于0),關(guān)于這個(gè)值的理解我們可以從下面兩個(gè)例子中獲取比較準(zhǔn)確的定義;

一、模擬多線程操作時(shí)幾個(gè)任務(wù)同時(shí)進(jìn)行,所有結(jié)果完成后才進(jìn)行處理
    dispatch_semaphore_t semaphoreControl = dispatch_semaphore_create(0);
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        NSLog(@"hoggen run task 1");
        sleep(1);
        NSLog(@"hoggen complete task 1");
        dispatch_semaphore_signal(semaphoreControl);
    });
    
    
    dispatch_async(queue, ^{
        NSLog(@"hoggen run task 2");
        sleep(2);
        NSLog(@"hoggen complete task 2");
        dispatch_semaphore_signal(semaphoreControl);
    });
    
    
    dispatch_async(queue, ^{
        NSLog(@"hoggen run task 3");
        sleep(3);
        NSLog(@"hoggen complete task 3");
        dispatch_semaphore_signal(semaphoreControl);
    });
    
    dispatch_async(queue, ^{
        NSLog(@"hoggen run task 4");
        sleep(4);
        NSLog(@"hoggen complete task 4");
        dispatch_semaphore_signal(semaphoreControl);
    });
    
    dispatch_async(queue, ^{
        dispatch_semaphore_wait(semaphoreControl, DISPATCH_TIME_FOREVER);
        dispatch_semaphore_wait(semaphoreControl, DISPATCH_TIME_FOREVER);
        dispatch_semaphore_wait(semaphoreControl, DISPATCH_TIME_FOREVER);
        dispatch_semaphore_wait(semaphoreControl, DISPATCH_TIME_FOREVER);
        NSLog(@"=================模擬多線程操作時(shí)幾個(gè)任務(wù)同時(shí)進(jìn)行,完成后才輸出結(jié)果======================");
    });
二、用于多線程,線程數(shù)量的控制
        dispatch_semaphore_t semaphore = dispatch_semaphore_create(2);
        dispatch_queue_t queue2 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        
        //任務(wù)1
        dispatch_async(queue2, ^{
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            NSLog(@"run task 1");
            sleep(1);
            NSLog(@"complete task 1");
            dispatch_semaphore_signal(semaphore);
        });
        //任務(wù)2
        dispatch_async(queue2, ^{
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            NSLog(@"run task 2");
            sleep(1);
            NSLog(@"complete task 2");
            dispatch_semaphore_signal(semaphore);
        });
        //任務(wù)3
        dispatch_async(queue2, ^{
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            NSLog(@"run task 3");
            sleep(1);
            NSLog(@"complete task 3");
            dispatch_semaphore_signal(semaphore);
        });

輸出結(jié)果為:

 =================semaphore信號(hào)量測試======================
 hoggen run task 2
 hoggen run task 1
 hoggen run task 3
hoggen run task 4
 run task 1
 run task 2
 hoggen complete task 1
complete task 1
complete task 2
 run task 3
 hoggen complete task 2
complete task 3
hoggen complete task 3
 hoggen complete task 4
=================模擬多線程操作時(shí)幾個(gè)任務(wù)同時(shí)進(jìn)行,完成后才輸出結(jié)果======================

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容