Objc多線程-GCD

基于C接口的線程調(diào)度。

dispatch_queue_attr_t : 定義一個queue的時候,用于指定queue的類型,queue的類型決定了queue里面的任務(wù)執(zhí)行的順序

DISPATCH_QUEUE_SERIAL:queue里面的任務(wù)由單個線程順序執(zhí)行

DISPATCH_QUEUE_CONCURRENT:queue里面的任務(wù)并發(fā)執(zhí)行,一般由多個線程負責執(zhí)行。

DISPATCH_QUEUE_SERIAL_INACTIVE

DISPATCH_QUEUE_CONCURRENT_INACTIVE:INACTIVE結(jié)尾的queue,往queue里面派發(fā)任務(wù)之前,必須先調(diào)用dispatch_activate(queue);

DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL

DISPATCH_QUEUE_CONCURRENT_WITH_AUTORELEASE_POOL

dispatch_async VS dispatch_sync

dispatch_async(queue, block);不阻塞當前線程。

dispatch_sync(queue,block);阻塞當前線程,直到任務(wù)執(zhí)行完畢。如果當前線程是主線程,queue又是main_queue,那么主線程會被卡死。

系統(tǒng)提供的兩個重要的queue

dispatch_queue_t? main_queue = dispatch_get_main_queue(); 主線程維護的全局可用的串行隊列,這個隊列與主線程的runLoop一起工作。

dispatch_queue_t global_queue = dispatch_get_global_queue(long identifier,unsigned long flags)。

identifer:可以使用qos_class_t中定義的服務(wù)質(zhì)量類或dispatch_queue_priority_t中定義的優(yōu)先級。

__QOS_ENUM(qos_class, unsigned int,

QOS_CLASS_USER_INTERACTIVE

__QOS_CLASS_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0) =0x21,

QOS_CLASS_USER_INITIATED

QOS_CLASS_DEFAULT

QOS_CLASS_UTILITY

QOS_CLASS_BACKGROUND

QOS_CLASS_UNSPECIFIED

);

typedef long dispatch_queue_priority_t;

參數(shù)flags:現(xiàn)階段暫時用不到,一般傳 0。


dispatch_time_t:設(shè)定一個調(diào)度時間。

方法1: dispatch_time_t? dispatchTime = dispatch_time(dispatch_time_t when, int64_t delta);

兩個特殊的dispatch_time_t。

DISPATCH_TIME_NOW

DISPATCH_TIME_FOREVER

#define NSEC_PER_SEC 1000000000ull // 1s

#define NSEC_PER_MSEC 1000000ull // 1ms

#define USEC_PER_SEC 1000000ull // 1ms

#define NSEC_PER_USEC 1000ull // 1μm

//舉例,表示距離現(xiàn)在10秒后時間點

dispatch_time_t newTime = dispatch_time(DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC);

方法2:dispatch_time_t dispatch_walltime(const struct timespec *_Nullable when, int64_t delta);

舉個栗子:

NSString * dateString = @"2018-08-08 08:08:08";

NSDateFormatter * formatDate = [[NSDateFormatter alloc] init];

formatDate.dateFormat = @"yyyy-MM-dd HH:mm:ss";

NSDate * yearDate = [formatDate dateFromString:dateString];

NSTimeInterval interval = [yearDate timeIntervalSince1970];

double second, subSecond;

struct timespec time;

// 將浮點數(shù)分解為整數(shù)和小數(shù)

subSecond = modf(interval, &second);

time.tv_sec = second;

time.tv_nsec = subSecond * NSEC_PER_SEC;

dispatch_time_t absoluteTime = dispatch_walltime(&time, 8 * NSEC_PER_SEC);

dispatch做延遲

dispatch_after(dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block);

dispatch_after函數(shù)不是在指定時間后執(zhí)行某種處理,而只是在指定時間將某種處理追加到Dispatch Queue中,但是不一定是立即執(zhí)行該處理!


dispatch_group_t:調(diào)度組。

GCD提供兩種方式支持dispatch并發(fā)隊列中的任務(wù)同步,即dispatch group和dispatch semaphore。

出現(xiàn)背景:并發(fā)隊列中的多個任務(wù),在線程池里面并發(fā)執(zhí)行的時候,需要知道所有任務(wù)執(zhí)行完成的時機,以便做一些處理。因此,dispatch_group_t一般作用于并發(fā)隊列。而串行隊列單線程順序執(zhí)行則不存在這種需求。

dispatch_group_t? group =dispatch_group_create();

dispatch_group_async(dispatch_group_t _Nonnull group, dispatch_queue_t _Nonnull cocurentQueue, ^{

});

void dispatch_group_notify(dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block);:該函數(shù)會一直等到組關(guān)聯(lián)的所有任務(wù)塊都已完成,然后再會將本函數(shù)將執(zhí)行的Block追加到Dispatch Queue中!

int state = dispatch_group_wait(group,dispatch_time(DISPATCH_TIME_NOW,0.000000000001*NSEC_PER_SEC));

group里面的任務(wù)執(zhí)行時間超過timeout后,state返回不為0,但是group里面的任務(wù)并沒有撤銷,而是繼續(xù)執(zhí)行。這個state只能反映出任務(wù)在timeout的時間內(nèi)是否能夠執(zhí)行完,而不能夠使得超時的任務(wù)撤銷。


還有兩個接口注意下。

下面的兩種調(diào)用其實是等價的,

A) dispatch_group_async(group, queue, ^{ // 。。。 });

B) dispatch_group_enter(group);

dispatch_async(queue, ^{ //。。。 dispatch_group_leave(group); });

下面是一個例子。

dispatch_group_t newGroup = dispatch_group_create();

dispatch_queue_t queue_change = dispatch_queue_create("com.atx610.NewMTX.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);

dispatch_group_async(newGroup, queue_change, ^{

sleep(1);

NSLog(@"test_1");

});

dispatch_group_async(newGroup, queue_change, ^{

NSLog(@"test_2");

});

dispatch_group_enter(newGroup);

dispatch_async(queue_change, ^{

NSLog(@"test_3");

dispatch_group_leave(newGroup);

});

dispatch_group_enter(newGroup);

dispatch_async(queue_change, ^{

sleep(2);

NSLog(@"test_4");

dispatch_group_leave(newGroup);

});

dispatch_group_notify(newGroup, queue_change, ^{

NSLog(@"done,and start new work");

});

//? ? dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC);

//? ? long result = dispatch_group_wait(newGroup, time);

//? ? if (result == 0) {

//? ? ? ? NSLog(@"在設(shè)置的時間內(nèi),組中的任務(wù)全部完成");

//? ? }else{

//? ? ? ? NSLog(@"在設(shè)置的時間內(nèi),組中的任務(wù)未全部完成");

//? ? }

調(diào)度墻:Dispatch Barrier

應(yīng)用場景:并發(fā)隊列中有若干個任務(wù),用戶希望這些任務(wù)能夠分批進行,一批結(jié)束,做一些操作或者不做任何操作,接著進行下一批。

注意事項:當提交到全局隊列(global queue)或未使用DISPATCH_QUEUE_CONCURRENT屬性創(chuàng)建的隊列時,Barrier Block與其他任務(wù)中的Block的行為相同!

void dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block); //異步執(zhí)行障礙Block?

void dispatch_barrier_sync(dispatch_queue_t queue, DISPATCH_NOESCAPE dispatch_block_t block);//同步執(zhí)行障礙Block?


與調(diào)用次數(shù)相關(guān)的接口:

void dispatch_apply(size_t iterations, dispatch_queue_t queue, DISPATCH_NOESCAPE void (^block)(size_t));:第一個參數(shù)iterations表示重復次數(shù),第三個參數(shù)block中有一個參數(shù),表示該block按照重復次數(shù)添加到queue中時是第幾個添加的。


void dispatch_once(dispatch_once_t *predicate, DISPATCH_NOESCAPE dispatch_block_t block);

信號量:dispatch semaphore

信號量解決的是一個車位不夠用的問題:

其中有3個重要接口:

1,dispatch_samaphore_t dispatch_semaphore_create(long value);

傳入的參數(shù)為long,輸出一個dispatch_semaphore_t類型且值為value的信號量。

值得注意的是,這里的傳入的參數(shù)value必須大于或等于0,否則dispatch_semaphore_create會返回NULL。

2,long dispatch_semaphore_wait(dispatch_semaphore_t ?dsema, dispatch_time_t timeout);

消費一個車位,timeout用于設(shè)定等車位的時間,超過后就不再等待了。

3,long dispatch_semaphore_signal(dispatch_semaphore_t dsema);

增加一個車位。


dispatch_queue_t global = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_semaphore_t semap = dispatch_semaphore_create(0);

dispatch_async(global, ^{

dispatch_semaphore_wait(semap, DISPATCH_TIME_FOREVER);

NSLog(@"first");

});

NSLog(@"second");

dispatch_semaphore_signal(semap);

output:

second

first

掛起和繼續(xù)執(zhí)行一個queue

dispatch_suspend(queue);

dispatch_resume(queue);

以上兩個要成對出現(xiàn),出現(xiàn)suspend,一定要有一個resume,不能無限制掛起。否則,會崩潰。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • GCD (Grand Central Dispatch) :iOS4 開始引入,使用更加方便,程序員只需要將任務(wù)添...
    池鵬程閱讀 1,361評論 0 2
  • 一、多線程簡介: 所謂多線程是指一個 進程 -- process(可以理解為系統(tǒng)中正在運行的一個應(yīng)用程序)中可以開...
    尋形覓影閱讀 1,078評論 0 6
  • Managing Units of Work(管理工作單位) 調(diào)度塊允許您直接配置隊列中各個工作單元的屬性。它們還...
    edison0428閱讀 8,032評論 0 1
  • 最近頗花了一番功夫把多線程GCD人的一些用法總結(jié)出來,一來幫自己鞏固一下知識、二來希望能幫到對這一塊還迷茫...
    人活一世閱讀 296評論 1 1
  • 你有沒有一段時間或者一個瞬間特別想念一個人。或許是親人或許是老友,又或許是埋在時光回憶里的那個Ta。 ...
    六月同學閱讀 344評論 0 0