iOS基础深入补完计划--GCD

(由于合在一起感觉一篇太长翻着累)

iOS多线程目前总结了四篇

欢迎移步O(∩_∩)O

目录

  • GCD
    • 队列dispatch_queue_t
    • 线程的开辟与阻塞机制
    • 一次性代码(单例)
    • 队列组
    • GCD定时器
    • 快速遍历dispatch_apply
    • 信号量
    • 线程栅栏
    • GCD的API

GCD

队列dispatch_queue_t

GCD中有两种队列、并且每种队列都有两种创建方式(系统默认+自定义)

  • 串行队列

1、主队列:

dispatch_get_main_queue()

2、自定义队列(串行):(参数为优先级、第二个参数DISPATCH_QUEUE_SERIAL实际上是指向'NULL'的宏)

dispatch_queue_create("queue_name", DISPATCH_QUEUE_SERIAL)
  • 并行队列

1、全局队列:(参数为优先级、第二个参数为0)

dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)

2、自定义队列(并行):

dispatch_queue_create("ss_queue", DISPATCH_QUEUE_CONCURRENT)

可以看出来、自定义队列都是使用dispatch_queue_create('队列名','队列类型')进行创建。

线程的开辟与阻塞机制

  • 并行和串行主要影响:任务的执行方式

并行:多个任务并发(同时)执行
串行:一个任务执行完毕后,再执行下一个任务

  • 同步和异步主要影响:能不能开启新的线程

同步:在当前线程中执行任务,不具备开启新线程的能力
异步:在新的线程中执行任务,具备开启新线程的能力

  • 会开辟新线程的两种情况

    • 并行队列+异步任务 = 多条新线程
    • 自定义串行多列+异步任务 = 一条新线程
  • 其余情况、全部将会置于当前线程/主线程(主队列任务)下执行。

GCD

用我们常用的代码举个例子:

dispatch_queue_t q = dispatch_queue_create("test.q", DISPATCH_QUEUE_CONCURRENT);

dispatch_async(q, ^{
    for (int i = 0; i < 100000; i ++) {
        NSLog(@"2--%d----%@",i,[NSThread currentThread]);
        sleep(3);
    }
});

dispatch_async(q, ^{
    for (int i = 0; i < 100000; i ++) {
       NSLog(@"1---%d----%@",i,[NSThread currentThread]);
       sleep(3);
    }
});

打印结果:

2018-03-19 15:32:12.591483+0800 test[5002:479872] 1---0----<NSThread: 0x600000278140>{number = 4, name = (null)}
2018-03-19 15:32:12.591549+0800 test[5002:479875] 2--0----<NSThread: 0x60400027b240>{number = 3, name = (null)}
2018-03-19 15:32:15.595894+0800 test[5002:479872] 1---1----<NSThread: 0x600000278140>{number = 4, name = (null)}
2018-03-19 15:32:15.595894+0800 test[5002:479875] 2--1----<NSThread: 0x60400027b240>{number = 3, name = (null)}
2018-03-19 15:32:18.601144+0800 test[5002:479872] 1---2----<NSThread: 0x600000278140>{number = 4, name = (null)}
2018-03-19 15:32:18.601144+0800 test[5002:479875] 2--2----<NSThread: 0x60400027b240>{number = 3, name = (null)}

这就是上面所说的并行队列+异步任务 = 多条新线程

如果我们把DISPATCH_QUEUE_CONCURRENT换成DISPATCH_QUEUE_SERIAL
打印结果又会变成

2018-03-19 15:40:20.491705+0800 test[5083:493760] 2--0----<NSThread: 0x600000278d00>{number = 3, name = (null)}
2018-03-19 15:40:23.493296+0800 test[5083:493760] 2--1----<NSThread: 0x600000278d00>{number = 3, name = (null)}
2018-03-19 15:40:26.497652+0800 test[5083:493760] 2--2----<NSThread: 0x600000278d00>{number = 3, name = (null)}

所有的输出都集中在number = 3的新线程中。

一次性代码(单例)

static id obj = nil;
+ (NSObject *)getObj
{
    static NSObject* obj;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        obj = [[NSObject alloc]init];
    });
    return obj;
}
  • dispatch_once的实现原理
- (NSObject *)getObj
{
    static NSObject* obj;
    static dispatch_once_t onceToken;
    NSLog(@"1::::%ld",onceToken);
    dispatch_once(&onceToken, ^{
        NSLog(@"2::::%ld",onceToken);
        obj = [[NSObject alloc]init];
        NSLog(@"3::::%ld",onceToken);
    });
    NSLog(@"4::::%ld",onceToken);
    return obj;
}

打印结果:

2018-03-20 18:08:04.066961+0800 test[5861:729479] 1::::0
2018-03-20 18:08:04.067124+0800 test[5861:729479] 2::::768
2018-03-20 18:08:04.067256+0800 test[5861:729479] 3::::768
2018-03-20 18:08:04.067355+0800 test[5861:729479] 4::::-1

所以

  • 当onceToken == 0 的时候、才允许进入函数内部执行初始化的block。
  • block执行完将onceToken修改。
  • (稍微扩展一下啊)当多个线程同时调用dispatch_once方法的时候、内部会借用信号量来进行线程控制、进一步保证每个block代码只执行一次。

更多的查看GCD外传:dispatch_once(上)细说@synchronized和dispatch_once

队列组dispatch_group

//队列组
- (void)dispatch_group_test {
    
    dispatch_queue_t queue = dispatch_queue_create("queue_test", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_t group = dispatch_group_create();
    
    dispatch_group_async(group, queue, ^{
        NSLog(@"任务1——准备休眠3秒");
        sleep(3);
        NSLog(@"任务1——完成");
    });
    
    NSLog(@"主线程——准备休眠5秒");
    sleep(5);
    NSLog(@"主线休眠结束");
    
    dispatch_group_async(group, queue, ^{
        NSLog(@"任务2——准备休眠10秒");
        sleep(10);
        NSLog(@"任务2——完成");
    });
    
    dispatch_group_notify(group, queue, ^{
        NSLog(@"任务组完成");
    });

    NSLog(@"主线程结束");
}

打印结果:

2018-03-20 10:43:32.135642+0800 test[1763:94602] 主线程——准备休眠5秒
2018-03-20 10:43:32.135649+0800 test[1763:94645] 任务1——准备休眠3秒
2018-03-20 10:43:35.141269+0800 test[1763:94645] 任务1——完成
2018-03-20 10:43:37.137225+0800 test[1763:94602] 主线休眠结束
2018-03-20 10:43:37.137513+0800 test[1763:94602] 主线程结束
2018-03-20 10:43:37.137515+0800 test[1763:94645] 任务2——准备休眠10秒
2018-03-20 10:43:47.139737+0800 test[1763:94645] 任务2——完成
2018-03-20 10:43:47.140116+0800 test[1763:94645] 任务组完成

这里可以扩展一下任务组的机制

  • dispatch_group_notify任务组的结束通知可以添加多次、并且会多次调用。
  • 类似于NSOperation中的依赖、GCD的group监听是可以追加的。只要任务组中的任务没有全部完成、group完成的监听不会被调用、哪怕是后追加的任务。
    GCD任务组
//队列组
- (void)dispatch_group_test {
    
    dispatch_queue_t queue = dispatch_queue_create("queue_test", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_t group = dispatch_group_create();
    
    dispatch_group_async(group, queue, ^{
        NSLog(@"任务1——准备休眠3秒");
        sleep(3);
        NSLog(@"任务1——完成");
    });
    
    NSLog(@"添加完成监听");
    dispatch_group_notify(group, queue, ^{
        NSLog(@"任务组完成");
    });

    dispatch_group_async(group, queue, ^{
        NSLog(@"任务2——准备休眠10秒");
        sleep(10);
        NSLog(@"任务2——完成");
    });

    NSLog(@"主线程结束");
}

打印结果

2018-03-20 10:49:16.192283+0800 test[1866:104770] 添加完成监听
2018-03-20 10:49:16.192284+0800 test[1866:104819] 任务1——准备休眠3秒
2018-03-20 10:49:16.192519+0800 test[1866:104770] 主线程结束
2018-03-20 10:49:16.192534+0800 test[1866:104930] 任务2——准备休眠10秒
2018-03-20 10:49:19.197851+0800 test[1866:104819] 任务1——完成
2018-03-20 10:49:26.198201+0800 test[1866:104930] 任务2——完成
2018-03-20 10:49:26.198583+0800 test[1866:104930] 任务组完成
  • 任务组是可以跨队列监听的
    所以、监听中的第二个参数(队列)到底是干嘛的~希望有大神指正

评论区已经有大神回复:
第二个参数决定了监听函数的callback将会在哪个队列执行。
比如你希望在异步任务完成之后、回到主线程刷新页面。

- (void)dispatch_group_test {
    
    dispatch_queue_t queue = dispatch_queue_create("queue_test", DISPATCH_QUEUE_CONCURRENT);
    dispatch_queue_t queue2 = dispatch_queue_create("queue_test", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_t group = dispatch_group_create();
    
    dispatch_group_async(group, queue2, ^{
        NSLog(@"任务1——准备休眠3秒");
        sleep(3);
        NSLog(@"任务1——完成");
    });
    
    NSLog(@"添加完成监听");
    dispatch_group_notify(group, queue, ^{
        NSLog(@"任务组完成");
    });

    NSLog(@"主线程结束");
}

打印结果:

2018-03-20 13:06:11.267924+0800 test[2243:234892] 添加完成监听
2018-03-20 13:06:11.267935+0800 test[2243:235001] 任务1——准备休眠3秒
2018-03-20 13:06:11.268402+0800 test[2243:234892] 主线程结束
2018-03-20 13:06:14.269280+0800 test[2243:235001] 任务1——完成
2018-03-20 13:06:14.269575+0800 test[2243:235001] 任务组完成

快速遍历dispatch_apply

GCD提供了多线程快速遍历的方法。需要注意的是:

  • 由于多线程遍历、输出的下标未必按照顺序排列。
  • 本质上是一个同步任务、而内部会使用一个并行队列用异步任务进行遍历。(所以如果需要、需要在外部自己开辟一个新的异步任务)
- (void)dispatch_apply_test {
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        dispatch_apply(10, queue, ^(size_t index) {
            NSLog(@"%@-%ld",[NSThread currentThread],index);
            sleep(10);
        });
        NSLog(@"任务完成");
    });
    NSLog(@"主线程结束");
}

打印结果:

2018-03-20 13:27:38.463507+0800 test[2491:271571] 主线程结束
2018-03-20 13:27:38.463630+0800 test[2491:271633] <NSThread: 0x60400026e180>{number = 3, name = (null)}-0
2018-03-20 13:27:38.463639+0800 test[2491:271928] <NSThread: 0x604000274680>{number = 4, name = (null)}-1
2018-03-20 13:27:38.463713+0800 test[2491:271932] <NSThread: 0x60000007ccc0>{number = 5, name = (null)}-2
2018-03-20 13:27:38.463715+0800 test[2491:271933] <NSThread: 0x60400026ecc0>{number = 6, name = (null)}-3
2018-03-20 13:27:48.468368+0800 test[2491:271932] <NSThread: 0x60000007ccc0>{number = 5, name = (null)}-6
2018-03-20 13:27:48.468368+0800 test[2491:271928] <NSThread: 0x604000274680>{number = 4, name = (null)}-4
2018-03-20 13:27:48.468382+0800 test[2491:271933] <NSThread: 0x60400026ecc0>{number = 6, name = (null)}-7
2018-03-20 13:27:48.468392+0800 test[2491:271633] <NSThread: 0x60400026e180>{number = 3, name = (null)}-5
2018-03-20 13:27:58.471068+0800 test[2491:271932] <NSThread: 0x60000007ccc0>{number = 5, name = (null)}-9
2018-03-20 13:27:58.471068+0800 test[2491:271933] <NSThread: 0x60400026ecc0>{number = 6, name = (null)}-8
2018-03-20 13:28:08.473167+0800 test[2491:271633] 任务完成

GCD定时器

不同于基于Runloop的NSTimerdispatch_source_t不会因为子线程没有正在运行的Runloop而失效、循环引用、计时不准(每次runloop循环才会检查定时器是否需要被执行)等问题。
也有几个点需要注意:

  • source最好被持有、不然在暂停dispatch_suspend的时候可能会Crash。
  • 暂停dispatch_suspend/开始resumeTimer一定要成对使用、否则会Crash。
  • dispatch_source_t并没有检查source本身状态的API。
@interface ViewController ()

@property (nonatomic, strong) dispatch_source_t timer;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    // 创建定时器,(dispatch_source_t本质是OC对象)
    self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());

    // 设置定时器的实践参数,时间参数一般是纳秒(1秒 == 10的9次方纳秒)为单位
    // 何时开始
    dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, (ino64_t)(1.0 * NSEC_PER_SEC));
    // 时间间隔
    uint64_t interval = (uint64_t)(2.0 * NSEC_PER_SEC);
    // 设置参数
    dispatch_source_set_timer(self.timer, start, interval, 0);

    // 设置回调,即设置需要定时器定时执行的操作
    dispatch_source_set_event_handler(self.timer, ^{

        NSLog(@"------");

    });

    // 启动定时器
    dispatch_resume(self.timer);

}

//暂停
-(void) pauseTimer{  
    if(_timer){  
        dispatch_suspend(_timer);  
    }  
}  
//恢复
-(void) resumeTimer{  
    if(_timer){  
        dispatch_resume(_timer);  
    }  
}  
//销毁
-(void) stopTimer{  
    if(_timer){  
        dispatch_source_cancel(_timer);  
        _timer = nil;  
    }  
}  

@end

信号量

信号量类似于锁。
简单来讲 信号量为0则阻塞线程,大于0则不会阻塞。则我们通过改变信号量的值,来控制是否阻塞线程,从而达到线程同步
GCD中的信号量含有三个函数:

  • dispatch_semaphore_create 创建一个semaphore信号量
  • dispatch_semaphore_signal 发送一个信号让信号量+1
  • dispatch_semaphore_wait 如果信号量计数为0则阻塞等待、否则通过。
    信号量

具体的使用举两个例子吧。

  • GCD控制并发数
    通过设置信号量初始值、达到GCD的并发。
// 创建队列组
    dispatch_group_t group = dispatch_group_create();   
// 创建信号量,并且设置值为10
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(10);   
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);   
    for (int i = 0; i < 100; i++)   
    {   // 由于是异步执行的,所以每次循环Block里面的dispatch_semaphore_signal根本还没有执行就会执行dispatch_semaphore_wait,从而semaphore-1.当循环10此后,semaphore等于0,则会阻塞线程,直到执行了Block的dispatch_semaphore_signal 才会继续执行
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);   
        dispatch_group_async(group, queue, ^{   
            NSLog(@"%i",i);   
            sleep(2);   
// 每次发送信号则semaphore会+1,
            dispatch_semaphore_signal(semaphore);   
        });   
    }
  • 异步任务转同步
    通过再方法末尾用信号量阻塞、直到异步请求完成后再通过。
    配合GCD任务组、NSOperation的依赖。可以达到多网络请求后的同步操作。
- (void)request1{
    //创建信号量并设置计数默认为0
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    manager.responseSerializer = [AFJSONResponseSerializer serializer];
    NSString *url = [NSString stringWithFormat:@"%s","http://v3.wufazhuce.com:8000/api/channel/movie/more/0?platform=ios&version=v4.0.1"];
    [manager GET:url parameters:nil progress:^(NSProgress * _Nonnull uploadProgress) {
        
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        NSArray *data = responseObject[@"data"];
        for (NSDictionary *dic in data) {
            NSLog(@"请求1---%@",dic[@"id"]);
        }
        //计数加1
        dispatch_semaphore_signal(semaphore);
        //11380-- data.lastObject[@"id"];
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSLog(@"shibai...");
        //计数加1
        dispatch_semaphore_signal(semaphore);
    }];
    //若计数为0则一直等待
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
}

线程栅栏dispatch_barrier

线程栅栏可以阻塞某个queue中任务的执行直到queue栅栏之前的任务被执行完毕。

- (void)dispatch_barrier_test {
    dispatch_queue_t queue = dispatch_queue_create("test_queue", DISPATCH_QUEUE_CONCURRENT);
    
    for (int i = 1; i <= 3; i ++) {
        dispatch_async(queue, ^{
            sleep(3);
            NSLog(@"任务%d结束",i);
        });
    }
    NSLog(@"代码经过栅栏");
    dispatch_barrier_sync(queue, ^{
        sleep(5);
        NSLog(@"栅栏结束");
    });
    NSLog(@"代码通过栅栏");
    
    for (int i = 4; i <= 6; i ++) {
        dispatch_async(queue, ^{
            sleep(3);
            NSLog(@"任务%d结束",i);
        });
    }
    NSLog(@"代码结束");
}

打印结果:

2018-03-20 16:44:07.347195+0800 test[4987:607391] 代码经过栅栏
2018-03-20 16:44:10.351954+0800 test[4987:607438] 任务1结束
2018-03-20 16:44:10.351954+0800 test[4987:607439] 任务3结束
2018-03-20 16:44:10.351984+0800 test[4987:607440] 任务2结束
2018-03-20 16:44:15.353557+0800 test[4987:607391] 栅栏结束
2018-03-20 16:44:15.353836+0800 test[4987:607391] 代码通过栅栏
2018-03-20 16:44:15.354086+0800 test[4987:607391] 代码结束
2018-03-20 16:44:18.357376+0800 test[4987:607441] 任务5结束
2018-03-20 16:44:18.357369+0800 test[4987:607440] 任务4结束
2018-03-20 16:44:18.357457+0800 test[4987:607438] 任务6结束

同步栅栏dispatch_barrier_sync换成异步栅栏dispatch_barrier_async

2018-03-20 16:45:52.798543+0800 test[5025:610657] 代码经过栅栏
2018-03-20 16:45:52.798700+0800 test[5025:610657] 代码通过栅栏
2018-03-20 16:45:52.798823+0800 test[5025:610657] 代码结束
2018-03-20 16:45:55.798703+0800 test[5025:610699] 任务1结束
2018-03-20 16:45:55.798722+0800 test[5025:610702] 任务3结束
2018-03-20 16:45:55.798725+0800 test[5025:610698] 任务2结束
2018-03-20 16:46:00.800958+0800 test[5025:610698] 栅栏结束
2018-03-20 16:46:03.805894+0800 test[5025:610701] 任务6结束
2018-03-20 16:46:03.805886+0800 test[5025:610698] 任务4结束
2018-03-20 16:46:03.805987+0800 test[5025:610702] 任务5结束

很明显的区别在于

  • 同步栅栏会阻塞之后普通代码的执行、异步栅栏则不会。
    应用线程栅栏的特性、我们可以更好的做一些线程同步。某些情况下不需要写好几层任务组来同步任务。
例如4/5/6任务想要等待1/2/3任务。
用任务组的的话、需要一个任务组包含(1/2/3)。
然后在任务组完成的回调中再并发出三个任务(4/5/6)。
而且还无法控制线程的阻塞、除非在想要阻塞的地方加入最后一个同步任务。
想想就很麻烦....

GCD的API

这部分不是我自己写的、在查阅一些API资料的途中翻到了这篇博客。
《iOS多线程之GCD》深表感谢。

/* 

功能:将块函数添加到线程队列中异步执行(异步:执行后不管结果直接返回)

参数:queue:指定的队列   block/work 块函数(context:传入block块函数中的参数)

返回值:空

*/

void dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

void dispatch_async_f(dispatch_queue_t queue,

void *_Nullable context,

dispatch_function_t work);

/* 

功能:将块函数添加到线程队列中同步执行(异步:执行完成后返回结果)

参数:queue:指定的队列   block/work 块函数(context:传入block块函数中的参数)

返回值:空

*/

void dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);

void dispatch_sync_f(dispatch_queue_t queue,

void *_Nullable context,

dispatch_function_t work);

/* 

功能:将块函数添加到线程队列中按照迭代次数执行,所有迭代完成后返回结果

参数:iterations:迭代次数  queue:指定的队列   block/work 块函数(context:传入block块函数中的参数)

返回值:空

*/

void dispatch_apply(size_t iterations, dispatch_queue_t queue,

DISPATCH_NOESCAPE void (^block)(size_t));

dispatch_apply_f(size_t iterations, dispatch_queue_t queue,

void *_Nullable context,

void (*work)(void *_Nullable, size_t));



/* 

功能:获取当前执行中的队列

参数:无

返回值:当前队列或者空

*/

dispatch_queue_t dispatch_get_current_queue(void);

/* 

功能:获取主队列

参数:无

返回值:主队列或者空

*/

dispatch_queue_t dispatch_get_main_queue(void)

{

return DISPATCH_GLOBAL_OBJECT(dispatch_queue_t, _dispatch_main_q);

}

/* 

功能:获取全局并发队列

参数:identifier:队列优先级  typedef long dispatch_queue_priority_t;

- DISPATCH_QUEUE_PRIORITY_HIGH:         QOS_CLASS_USER_INITIATED

- DISPATCH_QUEUE_PRIORITY_DEFAULT:      QOS_CLASS_DEFAULT

- DISPATCH_QUEUE_PRIORITY_LOW:          QOS_CLASS_UTILITY

- DISPATCH_QUEUE_PRIORITY_BACKGROUND:   QOS_CLASS_BACKGROUND



#define DISPATCH_QUEUE_PRIORITY_HIGH 2

#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0

#define DISPATCH_QUEUE_PRIORITY_LOW (-2)

#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN



  flags:保留供将来使用,输入除了0以外的任何值可能返回空值

返回值:全局队列或者空

*/

dispatch_queue_t dispatch_get_global_queue(long identifier, unsigned long flags);





#define DISPATCH_QUEUE_SERIAL NULL  //串行队列

#define DISPATCH_QUEUE_SERIAL_INACTIVE//暂停状态串行队列

dispatch_queue_attr_make_initially_inactive(DISPATCH_QUEUE_SERIAL)

#define DISPATCH_QUEUE_CONCURRENT //并发队列

DISPATCH_GLOBAL_OBJECT(dispatch_queue_attr_t, _dispatch_queue_attr_concurrent)

#define DISPATCH_QUEUE_CONCURRENT_INACTIVE  //暂停状态并发队列

dispatch_queue_attr_make_initially_inactive(DISPATCH_QUEUE_CONCURRENT)



/* 

功能:设置属性值,用于在队列的创建时加入

参数:attr:队列属性值

返回值:队列属性值

*/

dispatch_queue_attr_t dispatch_queue_attr_make_initially_inactive(

dispatch_queue_attr_t _Nullable attr);





#define DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL 

dispatch_queue_attr_make_with_autorelease_frequency(

DISPATCH_QUEUE_SERIAL, DISPATCH_AUTORELEASE_FREQUENCY_WORK_ITEM)



#define DISPATCH_QUEUE_CONCURRENT_WITH_AUTORELEASE_POOL

dispatch_queue_attr_make_with_autorelease_frequency(

 DISPATCH_QUEUE_CONCURRENT, DISPATCH_AUTORELEASE_FREQUENCY_WORK_ITEM)



dispatch_queue_attr_t dispatch_queue_attr_make_with_autorelease_frequency(

dispatch_queue_attr_t _Nullable attr,
dispatch_autorelease_frequency_t frequency);



/* 

功能:创建队列

参数:label:队列附带信息,可有可无  attr:队列属性值  target:目标队列,相当于目标队列计数加一

返回值:引用的队列

*/



dispatch_queue_t dispatch_queue_create(const char *_Nullable label,

dispatch_queue_attr_t _Nullable attr);



dispatch_queue_t dispatch_queue_create_with_target(const char *_Nullable label,

dispatch_queue_attr_t _Nullable attr, dispatch_queue_t _Nullable target)



/* 

功能:获取队列描述信息

参数:label:队列附带信息,可有可无  attr:队列属性值  target:目标队列,相当于目标队列计数加一

返回值:队列附带信息

*/

const char *dispatch_queue_get_label(dispatch_queue_t _Nullable queue);





//dispatch_qos_class_t dispatch_queue_get_qos_class(dispatch_queue_t queue,

int *_Nullable relative_priority_ptr);



/* 

功能:给指定对象设置目标队列

参数:object:目标对象  queue:目标队列

返回值:无

*/

void dispatch_set_target_queue(dispatch_object_t object,

dispatch_queue_t _Nullable queue);



/* 

功能:dispatch类入口函数

参数:无

返回值:无

*/

void dispatch_main(void);



/* 

功能:在指定时间后再目标队列执行block任务

参数:when:时间 queue:目标队列  block/work:要执行的任务  context:传入任务中的参数

返回值:无

*/

void dispatch_after(dispatch_time_t when,

dispatch_queue_t queue,

dispatch_block_t block);

void dispatch_after_f(dispatch_time_t when,

dispatch_queue_t queue,

void *_Nullable context,

dispatch_function_t work);



/* 

功能:给指定队列增加一个阻塞其它异步执行任务的任务

参数:queue:队列  block/work:任务  context:传入任务的参数

返回值:无

*/

void dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);

void dispatch_barrier_async_f(dispatch_queue_t queue,

void *_Nullable context,

dispatch_function_t work);

/* 

功能:给指定队列增加一个阻塞其它同步执行任务的任务

参数:queue:队列  block/work:任务  context:传入任务的参数

返回值:无

*/

void dispatch_barrier_sync(dispatch_queue_t queue,

DISPATCH_NOESCAPE dispatch_block_t block);

void dispatch_barrier_sync_f(dispatch_queue_t queue,

void *_Nullable context,

dispatch_function_t work);



/* 

功能:当指定队列键值改变时,或者是所有属性值都释放后,调用销毁函数destructor

参数:queue:队列  key:键名  context:新内容  destructor:销毁函数

返回值:无

*/

void dispatch_queue_set_specific(dispatch_queue_t queue, const void *key,

void *_Nullable context, dispatch_function_t _Nullable destructor);



/* 

功能:获取指定队列特定键内容

参数:queue:队列  key:键名  

返回值:键值

*/

void *_Nullable dispatch_queue_get_specific(dispatch_queue_t queue, const void *key);

/* 

功能:获取当前队列特定键内容

参数: key:键名  

返回值:键值

*/

void *_Nullable dispatch_get_specific(const void *key);



/* 

功能:验证当前块任务运行在指定队列上

参数:queue:队列 

返回值:无

*/

void dispatch_assert_queue(dispatch_queue_t queue)

DISPATCH_ALIAS_V2(dispatch_assert_queue);

/* 

功能:验证当前块任务运行在指定队列上,并且该任务阻塞队列中的其它任务

参数:queue:队列 

返回值:无

*/

void dispatch_assert_queue_barrier(dispatch_queue_t queue);

/* 

功能:验证当前块任务没有运行在指定队列上

参数:queue:队列 

返回值:无

*/

void dispatch_assert_queue_not(dispatch_queue_t queue)

DISPATCH_ALIAS_V2(dispatch_assert_queue_not);







/******************************************************dispatch—group****************************************************/



/* 

功能:创建派遣队列组

参数:无

返回值:队列组

*/

dispatch_group_t dispatch_group_create(void);

/* 

功能:给指定队列添加异步执行任务,将队列加入组

参数:group:队列组 queue:指定队列  block/work:任务  context:传入任务的参数

返回值:无

*/

void dispatch_group_async(dispatch_group_t group,

dispatch_queue_t queue,

dispatch_block_t block);



void dispatch_group_async_f(dispatch_group_t group,

dispatch_queue_t queue,

void *_Nullable context,

dispatch_function_t work);

/* 

功能:等待(阻塞线程)一直到(队列组中所有任务执行结束或者是时间结束)

参数:group:队列组 timeout:时间

返回值:0表示成功,非0.错误

*/

long dispatch_group_wait(dispatch_group_t group, dispatch_time_t timeout);

/* 

功能:队列组中所有任务执行结束之后,执行新的block 任务

参数:group:任务组 queue:指定队列  block/work:新任务  context:传入任务的参数

返回值:任务组

*/

void dispatch_group_notify(dispatch_group_t group,

dispatch_queue_t queue,

dispatch_block_t block);



void dispatch_group_notify_f(dispatch_group_t group,

dispatch_queue_t queue,

void *_Nullable context,

dispatch_function_t work);



/* 

功能:管理显示队列组中所有任务

参数:group:队列组 

返回值:队列组

*/

void dispatch_group_enter(dispatch_group_t group);

/* 

功能:管理显示队列组中以执行结束的任务

参数:group:队列组

返回值:队列组

*/

void dispatch_group_leave(dispatch_group_t group);



/******************************************************dispatch—semaphore****************************************************/



/* 

功能:创建信号量

参数:value:信号量资源数

返回值:信号量或空(失败)

*/

dispatch_semaphore_t dispatch_semaphore_create(long value);

/* 

功能:等待获取信号量,获取到后开始继续执行,或是时间结束

参数:dsema:信号量 timeout:限定时间

返回值:无

*/

long dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);

/* 

功能:执行结束,不需要占用资源,释放信号量

参数:dsema:信号量

返回值:无

*/

long dispatch_semaphore_signal(dispatch_semaphore_t dsema);



/******************************************************dispatch—object****************************************************/



/* 

功能:增加队列引用计数

参数:object:操作队列

返回值:无

*/

void dispatch_retain(dispatch_object_t object);

/* 

功能:减少队列引用计数

参数:object:操作队列

返回值:无

*/

void dispatch_release(dispatch_object_t object);

/* 

功能:获取对象应用程序上下文

参数:object:对象

返回值:定义内容或空

*/

void *_Nullable dispatch_get_context(dispatch_object_t object);

/* 

功能:设置指定对象的应用程序上下文

参数:object:对象 context:上下文内容

返回值:无

*/

void dispatch_set_context(dispatch_object_t object, void *_Nullable context);

/* 

功能:设置对象销毁函数,在该对象所有引用释放后,销毁该对象

参数:object:对象 finalizer:销毁函数指针

返回值:无

*/

void dispatch_set_finalizer_f(dispatch_object_t object,

dispatch_function_t _Nullable finalizer);

/* 

功能:激活指定非活动对象

参数:object:对象(一般是线程队列) 

返回值:无

*/

void dispatch_activate(dispatch_object_t object);

/* 

功能:挂起/阻塞指定对象(一般是线程队列)

参数:object:对象 

返回值:无

*/

void dispatch_suspend(dispatch_object_t object);

/* 

功能:恢复指定对象(一般是线程队列)

参数:object:对象 

返回值:无

*/

void dispatch_resume(dispatch_object_t object);

/* 

功能:同步等待一个对象完成操作,或者是直到超出规定时间

参数:object:对象  timeout:限定时间

返回值:0成功,非0失败

*/

long dispatch_wait(void *object, dispatch_time_t timeout);

/* 

功能:在指定对象完成工作后,将一个通知块任务加入指定队列

参数:object:对象  queue:队列 notification_block:通知块

返回值:无

*/

void dispatch_notify(void *object, dispatch_object_t queue,

dispatch_block_t notification_block);

/* 

功能:取消指定对象

参数:object:对象 

返回值:无

*/

void dispatch_cancel(void *object);

/* 

功能:判断指定对象是否被取消

参数:object:对象 

返回值:0表示未取消,其它表示取消

*/

long dispatch_testcancel(void *object);

/* 

功能:已编程方式记录指定对象的调试调度信息

参数:object:对象 

返回值:无

*/

void dispatch_debug(dispatch_object_t object, const char *message, ...);

void dispatch_debugv(dispatch_object_t object, const char *message, va_list ap);





/******************************************************dispatch—once****************************************************/



/* 

功能:只执行任务函数一次

参数:predicate:dispatch_once_t 对象  block/function要执行的任务函数 context:传入的内容

返回值:无

*/

void dispatch_once(dispatch_once_t *predicate,

DISPATCH_NOESCAPE dispatch_block_t block);

void dispatch_once_f(dispatch_once_t *predicate, void *_Nullable context,

dispatch_function_t function);



/******************************************************dispatch—time****************************************************/



/* 

功能:创建时间对象,在指定时间的基础上再添加一段时间

参数:when:时间  delta:时间段(纳秒)

返回值:时间对象

*/

dispatch_time_t dispatch_time(dispatch_time_t when, int64_t delta);



/* 

功能:创建时间对象,在指定时间的基础上再添加一段时间

参数:when:时间  delta时间段(纳秒)

返回值:时间对象

*/

dispatch_time_t dispatch_walltime(const struct timespec *_Nullable when, int64_t delta);

最后

本文主要是自己的学习与总结。如果文内存在纰漏、万望留言斧正。如果不吝赐教小弟更加感谢。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,723评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,080评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,604评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,440评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,431评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,499评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,893评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,541评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,751评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,547评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,619评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,320评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,890评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,896评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,137评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,796评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,335评论 2 342