美文网首页
iOS 多线程 GCD

iOS 多线程 GCD

作者: 青椒辣不辣 | 来源:发表于2020-12-10 18:28 被阅读0次
  • 全称是Grand Central Dispatch,可译为“牛逼的中枢调度器”
  • 纯C语言,提供了非常多强大的函数
  • GCD的优势
  • GCD是苹果公司为多核的并行运算提出的解决方案
  • GCD会自动利用更多的CPU内核(比如双核、四核)
  • GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)
  • 程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码
同步和异步:决定的是任务的执行方式
     同步: 如果我没有执行完,那么后面的将永远无法执行
     异步:我无所谓,我没执行完后面的也可以执行
同步函数和异步函数:disaptach_sync| disaptach_async
     同步函数:
        特点:只能在当前线程中执行任务,不具备开启新线程的能力
        执行方式:同步
     异步函数:
        特点:可以在新的线程中执行任务,具备开启新线程的能力
        执行方式:异步
GCD中的队列
     1)并发队列:
        (1)直接创建      dispatch_queue_create DISPATCH_QUEUE_CONCURRENT
        (2)全局并发队列  dispatch_get_global_queue
     2)串行队列:
        (1)直接创建      dispatch_queue_create DISPATCH_QUEUE_SERIAL
        (2)主队列        dispatch_get_main_queue
            a.凡是放在主队列中的任务都必须要在主线程中执行
            b.该队列是默认存在的
            c.主队列在调度任务之前会先检查主线程当前状态,如果主线程忙则暂停调度

\color{rgb(0 ,139, 139)}{全局并发队列}

/*
    获得全局并发队列
    系统内部默认提供4个全局并发队列
    第一个参数:队列的优先级
    第二个参数:留给未来使用 传0
    #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
     */
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    //2.使用函数封装任务并且把任务添加到队列中
    for (int i = 0; i < 10; i ++) {
        dispatch_async(queue, ^{
            NSLog(@"%d----%@",i,[NSThread currentThread]);
        });
    }

0----<NSThread: 0x600002fa4f40>{number = 7, name = (null)}
1----<NSThread: 0x600002fbccc0>{number = 6, name = (null)}
5----<NSThread: 0x600002ffa2c0>{number = 3, name = (null)}
4----<NSThread: 0x600002fbccc0>{number = 6, name = (null)}
6----<NSThread: 0x600002ffa2c0>{number = 3, name = (null)}
8----<NSThread: 0x600002fbccc0>{number = 6, name = (null)}
9----<NSThread: 0x600002ffa2c0>{number = 3, name = (null)}
7----<NSThread: 0x600002fbf2c0>{number = 5, name = (null)}
3----<NSThread: 0x600002fa4f40>{number = 7, name = (null)}
2----<NSThread: 0x600002fe7e40>{number = 4, name = (null)}

\color{rgb(0 ,139, 139)}{异步函数+主队列}不会开启新的线程,所有的任务都在主线程中串行执行

    dispatch_queue_t queue = dispatch_get_main_queue();
    for (int i = 0; i < 10; i ++) {
        dispatch_async(queue, ^{
            NSLog(@"%d----%@",i,[NSThread currentThread]);
        });
    }

0----<NSThread: 0x6000016b4980>{number = 1, name = main}
1----<NSThread: 0x6000016b4980>{number = 1, name = main}
2----<NSThread: 0x6000016b4980>{number = 1, name = main}
3----<NSThread: 0x6000016b4980>{number = 1, name = main}
4----<NSThread: 0x6000016b4980>{number = 1, name = main}
5----<NSThread: 0x6000016b4980>{number = 1, name = main}
6----<NSThread: 0x6000016b4980>{number = 1, name = main}
7----<NSThread: 0x6000016b4980>{number = 1, name = main}
8----<NSThread: 0x6000016b4980>{number = 1, name = main}
9----<NSThread: 0x6000016b4980>{number = 1, name = main}

\color{rgb(0 ,139, 139)}{异步函数+串行队列}开起了一条子线程,队列里面的任务是串行执行的

    dispatch_queue_t queue = dispatch_queue_create("RJCustomTool", DISPATCH_QUEUE_SERIAL);
    for (int i = 0; i < 10; i ++) {
        dispatch_async(queue, ^{
            NSLog(@"%d----%@",i,[NSThread currentThread]);
        });
    }
0----<NSThread: 0x600002860a80>{number = 7, name = (null)}
1----<NSThread: 0x600002860a80>{number = 7, name = (null)}
2----<NSThread: 0x600002860a80>{number = 7, name = (null)}
3----<NSThread: 0x600002860a80>{number = 7, name = (null)}
4----<NSThread: 0x600002860a80>{number = 7, name = (null)}
5----<NSThread: 0x600002860a80>{number = 7, name = (null)}
6----<NSThread: 0x600002860a80>{number = 7, name = (null)}
7----<NSThread: 0x600002860a80>{number = 7, name = (null)}
8----<NSThread: 0x600002860a80>{number = 7, name = (null)}
9----<NSThread: 0x600002860a80>{number = 7, name = (null)}

\color{rgb(0 ,139, 139)}{异步函数+并发队列}会开多条子线程,队列中的任务是并发执行的

    dispatch_queue_t queue = dispatch_queue_create("RJCustomTool", DISPATCH_QUEUE_CONCURRENT);
    for (int i = 0; i < 10; i ++) {
        dispatch_async(queue, ^{
            NSLog(@"%d----%@",i,[NSThread currentThread]);
        });
    }
1----<NSThread: 0x6000038785c0>{number = 6, name = (null)}
3----<NSThread: 0x6000038641c0>{number = 5, name = (null)}
5----<NSThread: 0x6000038785c0>{number = 6, name = (null)}
2----<NSThread: 0x60000383fb00>{number = 7, name = (null)}
7----<NSThread: 0x6000038641c0>{number = 5, name = (null)}
4----<NSThread: 0x60000383ef80>{number = 8, name = (null)}
9----<NSThread: 0x60000383fb00>{number = 7, name = (null)}
6----<NSThread: 0x600003878e00>{number = 4, name = (null)}
0----<NSThread: 0x600003865f40>{number = 3, name = (null)}
8----<NSThread: 0x6000038785c0>{number = 6, name = (null)}

\color{rgb(0 ,139, 139)}{同步函数+主队列}不会开启新的线程,所有的任务都在主线程中串行执行(死锁)
\color{rgb(255,20,147)}{ps:主线程中开启会死锁}

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [NSThread detachNewThreadSelector:@selector(task) toTarget:self withObject:nil];
}
-(void)task{
    NSLog(@"%@",[NSThread currentThread]);
    dispatch_queue_t queue = dispatch_get_main_queue();
    for (int i = 0; i < 10; i ++) {
        dispatch_sync(queue, ^{
            NSLog(@"%d----%@",i,[NSThread currentThread]);
        });
    }
}
<NSThread: 0x600002b9ce00>{number = 6, name = (null)}
0----<NSThread: 0x600001aec980>{number = 1, name = main}
1----<NSThread: 0x600001aec980>{number = 1, name = main}
2----<NSThread: 0x600001aec980>{number = 1, name = main}
3----<NSThread: 0x600001aec980>{number = 1, name = main}
4----<NSThread: 0x600001aec980>{number = 1, name = main}
5----<NSThread: 0x600001aec980>{number = 1, name = main}
6----<NSThread: 0x600001aec980>{number = 1, name = main}
7----<NSThread: 0x600001aec980>{number = 1, name = main}
8----<NSThread: 0x600001aec980>{number = 1, name = main}
9----<NSThread: 0x600001aec980>{number = 1, name = main}

\color{rgb(0 ,139, 139)}{同步函数+串行队列}不会开启新的线程,所有的任务在当前线程中串行执行

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [NSThread detachNewThreadSelector:@selector(task) toTarget:self withObject:nil];
}
-(void)task{
    NSLog(@"%@",[NSThread currentThread]);
    dispatch_queue_t queue = dispatch_queue_create("RJCustomTool", DISPATCH_QUEUE_SERIAL);
    for (int i = 0; i < 10; i ++) {
        dispatch_sync(queue, ^{
            NSLog(@"%d----%@",i,[NSThread currentThread]);
        });
    }
}
<NSThread: 0x600000b508c0>{number = 8, name = (null)}
0----<NSThread: 0x600000b508c0>{number = 8, name = (null)}
1----<NSThread: 0x600000b508c0>{number = 8, name = (null)}
2----<NSThread: 0x600000b508c0>{number = 8, name = (null)}
3----<NSThread: 0x600000b508c0>{number = 8, name = (null)}
4----<NSThread: 0x600000b508c0>{number = 8, name = (null)}
5----<NSThread: 0x600000b508c0>{number = 8, name = (null)}
6----<NSThread: 0x600000b508c0>{number = 8, name = (null)}
7----<NSThread: 0x600000b508c0>{number = 8, name = (null)}
8----<NSThread: 0x600000b508c0>{number = 8, name = (null)}
9----<NSThread: 0x600000b508c0>{number = 8, name = (null)}

\color{rgb(0 ,139, 139)}{同步函数+并发队列}不会开启新的线程,所有的任务在当前线程中串行执行

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [NSThread detachNewThreadSelector:@selector(task) toTarget:self withObject:nil];
}
-(void)task{
    NSLog(@"%@",[NSThread currentThread]);
    dispatch_queue_t queue = dispatch_queue_create("RJCustomTool", DISPATCH_QUEUE_CONCURRENT);
    for (int i = 0; i < 10; i ++) {
        dispatch_sync(queue, ^{
            NSLog(@"%d----%@",i,[NSThread currentThread]);
        });
    }
}
<NSThread: 0x600000f3cdc0>{number = 7, name = (null)}
0----<NSThread: 0x600000f3cdc0>{number = 7, name = (null)}
1----<NSThread: 0x600000f3cdc0>{number = 7, name = (null)}
2----<NSThread: 0x600000f3cdc0>{number = 7, name = (null)}
3----<NSThread: 0x600000f3cdc0>{number = 7, name = (null)}
4----<NSThread: 0x600000f3cdc0>{number = 7, name = (null)}
5----<NSThread: 0x600000f3cdc0>{number = 7, name = (null)}
6----<NSThread: 0x600000f3cdc0>{number = 7, name = (null)}
7----<NSThread: 0x600000f3cdc0>{number = 7, name = (null)}
8----<NSThread: 0x600000f3cdc0>{number = 7, name = (null)}
9----<NSThread: 0x600000f3cdc0>{number = 7, name = (null)}

\color{rgb(0 ,139, 139)}{线程间通信}子线程->主线程(嵌套&使用主队列)

    dispatch_async(dispatch_get_global_queue(0,0), ^{//开启全局并发队列下载图片
        NSURL *url = [NSURL URLWithString:@"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1607584191107&di=dabaca87bbdb1c938cebc378ccd85480&imgtype=0&src=http%3A%2F%2Fattachments.gfan.com%2Fforum%2Fattachments2%2F201306%2F06%2F144906n0nffsz8h43i1t23.jpg"];
        NSData *imageData = [NSData dataWithContentsOfURL:url];
        UIImage *image = [UIImage imageWithData:imageData];
        
        dispatch_async(dispatch_get_main_queue(), ^{//回到主线程设置UI
            self.imageView.image = image;
        });
    });

\color{rgb(0 ,139, 139)}{延迟执行}NSObject--NSTimer--GCD

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [self performSelector:@selector(task) withObject:nil afterDelay:2.0];
    [NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(task) userInfo:nil repeats:NO];
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"GCD----%@",[NSThread currentThread]);
        });
}
-(void)task{
    NSLog(@"%@",[NSThread currentThread]);
}

<NSThread: 0x600003b74b00>{number = 1, name = main}
<NSThread: 0x600003b74b00>{number = 1, name = main}
GCD----<NSThread: 0x600003b74b00>{number = 1, name = main}

\color{rgb(0 ,139, 139)}{定时器}
dispatch_source_cancel(timer) 之后 dispatch_resume(timer) 会报错:Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    
    //1.创建一个GCD的定时器
    /*
     第一个参数:DISPATCH_SOURCE_TYPE_TIMER 定时器
     第二个参数:描述信息
     第三个参数:总是传0
     第四个参数:队列 (决定GCD要执行的任务在哪个线程中调用的 并发队列--子线程中调用:dispatch_get_global_queue(0,0) 传主队列 —主线程中调用:dispatch_get_main_queue())*/
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0,0));
    
    //2.设置定时器
    /*
     第一个参数:定时器对象
     第二个参数:从什么时候开始计时 DISPATCH_TIME_NOW 现在
     第三个参数:间隔时间 2.0 ns
     第四个参数:精准度 允许的误差  绝对精准~0
     ——>dispatch_time_t t = dispatch_time(DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC);<--*/
    dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
    //3.设置定时器的任务
    __block NSInteger number = 10;
    dispatch_source_set_event_handler(timer, ^{
        if (number < 5) {
            NSLog(@"dispatch_source_cancel===%@",[NSThread currentThread]);
            //dispatch_source_cancel(timer); //Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
            dispatch_suspend(timer);//暂停
        }else{
            NSLog(@"dispatch_source_set_event_handler--%ld===%@",number,[NSThread currentThread]);
            number--;
        }
    });
    dispatch_resume(timer);
    
    // 8秒后继续定时器
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(8.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"dispatch_after----%@",[NSThread currentThread]);
        number = 8;
        dispatch_resume(timer);
    });
}

dispatch_source_set_event_handler--10===<NSThread: 0x6000009729c0>{number = 3, name = (null)}
dispatch_source_set_event_handler--9===<NSThread: 0x600000970680>{number = 5, name = (null)}
dispatch_source_set_event_handler--8===<NSThread: 0x6000009729c0>{number = 3, name = (null)}
dispatch_source_set_event_handler--7===<NSThread: 0x600000970680>{number = 5, name = (null)}
dispatch_source_set_event_handler--6===<NSThread: 0x600000970680>{number = 5, name = (null)}
dispatch_source_set_event_handler--5===<NSThread: 0x6000009729c0>{number = 3, name = (null)}
dispatch_source_cancel===<NSThread: 0x600000970680>{number = 5, name = (null)}
dispatch_after----<NSThread: 0x60000093c1c0>{number = 1, name = main}
dispatch_source_set_event_handler--8===<NSThread: 0x600000970680>{number = 5, name = (null)}
dispatch_source_set_event_handler--7===<NSThread: 0x600000970680>{number = 5, name = (null)}
dispatch_source_set_event_handler--6===<NSThread: 0x600000970680>{number = 5, name = (null)}
dispatch_source_set_event_handler--5===<NSThread: 0x600000970680>{number = 5, name = (null)}
dispatch_source_cancel===<NSThread: 0x6000009729c0>{number = 3, name = (null)}

\color{rgb(0 ,139, 139)}{一次性代码}能够保证在整个程序运行过程中,block中的代码段只会被执行一次 --- 线程安全 --- 应用:单例模式

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

\color{rgb(0 ,139, 139)}{栅栏函数}能够控制并发队列里面任务的执行顺序

  • dispatch_barrier_async:用于提交异步执行栅栏函数块任务,并立即返回.所以该函数不会阻塞线程,只会阻塞任务执行。栅栏函数提交之后并不会立即执行,而是会直接返回。等待在栅栏函数之前提交的任务都执行完成之后,栅栏函数任务会自动执行,在栅栏函数之后提交的任务必须在栅栏函数执行完成之后才会执行.
  • dispatch_barrier_sync:用于提交同步执行栅栏函数块任务,并不会立即返回,需要等待栅栏函数提交的任务执行完毕之后才会返回。与dispatch_barrier_async不同,由于该函数需要同步执行,在该栅栏函数任务执行完成之前,函数不会返回,所以此时后边的任务都会被阻塞.

注意:不能使用全局并发队列 (relevant only on DISPATCH_QUEUE_CONCURRENT queues).


dispatch_barrier_async

    dispatch_queue_t queue = dispatch_queue_create("RJCustomTool", DISPATCH_QUEUE_CONCURRENT);
    for (int i = 0; i < 10; i ++) {
        dispatch_async(queue, ^{
            NSLog(@"task %d --- %@",i, [NSThread currentThread]);
        });
    }
    dispatch_barrier_async(queue, ^{
        NSLog(@"dispatch_barrier_async --- %@", [NSThread currentThread]);
    });
    NSLog(@"task end --- %@", [NSThread currentThread]);
task end --- <NSThread: 0x600003b703c0>{number = 1, name = main}
task 2 --- <NSThread: 0x600003b20a40>{number = 6, name = (null)}
task 4 --- <NSThread: 0x600003b75e80>{number = 5, name = (null)}
task 5 --- <NSThread: 0x600003b14040>{number = 8, name = (null)}
task 6 --- <NSThread: 0x600003b20a40>{number = 6, name = (null)}
task 8 --- <NSThread: 0x600003b75e80>{number = 5, name = (null)}
task 1 --- <NSThread: 0x600003b76f40>{number = 3, name = (null)}
task 0 --- <NSThread: 0x600003b38a00>{number = 4, name = (null)}
task 3 --- <NSThread: 0x600003b2a100>{number = 7, name = (null)}
task 7 --- <NSThread: 0x600003b76e40>{number = 9, name = (null)}
task 9 --- <NSThread: 0x600003b20a40>{number = 6, name = (null)}
dispatch_barrier_async --- <NSThread: 0x600003b20a40>{number = 6, name = (null)}

dispatch_barrier_sync

    dispatch_queue_t queue = dispatch_queue_create("RJCustomTool", DISPATCH_QUEUE_CONCURRENT);
    for (int i = 0; i < 10; i ++) {
        dispatch_async(queue, ^{
            NSLog(@"task %d --- %@",i, [NSThread currentThread]);
        });
    }
    dispatch_barrier_sync(queue, ^{
        NSLog(@"dispatch_barrier_async --- %@", [NSThread currentThread]);
    });
    NSLog(@"task end --- %@", [NSThread currentThread]);
task 1 --- <NSThread: 0x6000036e71c0>{number = 6, name = (null)}
task 2 --- <NSThread: 0x6000036e0800>{number = 5, name = (null)}
task 4 --- <NSThread: 0x6000036a1e80>{number = 7, name = (null)}
task 6 --- <NSThread: 0x6000036e71c0>{number = 6, name = (null)}
task 7 --- <NSThread: 0x6000036e0800>{number = 5, name = (null)}
task 8 --- <NSThread: 0x6000036a1e80>{number = 7, name = (null)}
task 5 --- <NSThread: 0x6000036ef480>{number = 8, name = (null)}
task 0 --- <NSThread: 0x6000036e01c0>{number = 4, name = (null)}
task 3 --- <NSThread: 0x6000036a3300>{number = 3, name = (null)}
task 9 --- <NSThread: 0x6000036e71c0>{number = 6, name = (null)}
dispatch_barrier_async --- <NSThread: 0x6000036a43c0>{number = 1, name = main}
task end --- <NSThread: 0x6000036a43c0>{number = 1, name = main}

\color{rgb(0 ,139, 139)}{快速迭代}快速迭代不能使用主队列

1)for循环和apply的区别(for是在当前线程中串行执行)
        01)主线程和子线程一起执行迭代任务
        02)所有的任务是在多个线程(包含主线程)中并发执行
2)如何拼接文件全路径(stringByAppendingPathComponent
3)NSFileManager的基本使用(获得路径下面所有子路径&剪切文件)
4)注意点:快速迭代不能使用主队列
使用dispatch_get_main_queue报错:Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)


    dispatch_apply(10, dispatch_get_global_queue(0, 0), ^(size_t i) {
        NSLog(@"%zd---%@",i,[NSThread currentThread]);
    });
    NSLog(@"---end")

0---<NSThread: 0x600000a14280>{number = 1, name = main}
3---<NSThread: 0x600000a14280>{number = 1, name = main}
1---<NSThread: 0x600000a5ce00>{number = 4, name = (null)}
4---<NSThread: 0x600000a1c340>{number = 6, name = (null)}
7---<NSThread: 0x600000a5ce00>{number = 4, name = (null)}
5---<NSThread: 0x600000a14280>{number = 1, name = main}
8---<NSThread: 0x600000a1c340>{number = 6, name = (null)}
2---<NSThread: 0x600000a52c80>{number = 5, name = (null)}
9---<NSThread: 0x600000a5ce00>{number = 4, name = (null)}
6---<NSThread: 0x600000a1e300>{number = 7, name = (null)}
---end

\color{rgb(0 ,139, 139)}{快速迭代}剪切文件

/Users/jintian/Desktop/from
    //1.获得文件原始路径(上层文件夹得路径)
    NSString *fromPath = @"/Users/jintian/Desktop/from";
    //2.获得文件的目标路径
    NSString *toPath = @"/Users/jintian/Desktop/to";
    //3.得到文件路径下面的所有文件(3)
    NSArray *subpaths =  [[NSFileManager defaultManager] subpathsAtPath:fromPath];
    NSInteger count = subpaths.count;
    
    dispatch_apply(count, dispatch_get_global_queue(0, 0), ^(size_t index){
        NSLog(@"%zd---%@",index,[NSThread currentThread]);
        //4.拼接全路径
        NSString *fromFullpath = [fromPath stringByAppendingPathComponent:subpaths[index]];
        NSString *toFullpath = [toPath stringByAppendingPathComponent:subpaths[index]];
        //5.执行文件剪切操作
        //第一个参数:文件在哪里的全路径
        //第二个参数:文件要被剪切到哪里的全路径
        [[NSFileManager defaultManager] moveItemAtPath:fromFullpath toPath:toFullpath error:nil];
    });

0---<NSThread: 0x60000346ca40>{number = 1, name = main}
2---<NSThread: 0x600003434d40>{number = 7, name = (null)}
3---<NSThread: 0x60000343c200>{number = 8, name = (null)}
1---<NSThread: 0x6000034211c0>{number = 5, name = (null)}
4---<NSThread: 0x600003424840>{number = 3, name = (null)}
5---<NSThread: 0x600003469640>{number = 6, name = (null)}
6---<NSThread: 0x6000034211c0>{number = 5, name = (null)}
7---<NSThread: 0x600003434d40>{number = 7, name = (null)}
8---<NSThread: 0x60000346ca40>{number = 1, name = main}
9---<NSThread: 0x600003424840>{number = 3, name = (null)}
10---<NSThread: 0x600003469640>{number = 6, name = (null)}

\color{rgb(0 ,139, 139)}{队列组}待研究

 1)队列组的第一种用法(推荐)
    (1)创建队列组 dispatch_group_create()
              dispatch_group_t group = dispatch_group_create();
    (2)队列组监听任务的执行 dispatch_group_async
    (3)拦截通知 dispatch_group_notify(注意:该方法是异步的)
       dispatch_group_notify(group, queue, ^{  });
 2)队列组的第二种用法(能看懂别人的代码)
    (1)dispatch_group_enter(组名) & dispatch_group_leave(组名) 必须成对使用
    (2)dispatch_group_wait的用法(注意:该方法本身是同步的)
          不管队列中的任务有没有执行完毕都继续往下执行,如果在该时间内所有事任务都执行完毕了那么会返回一个0,否则是非0值
    long n =  dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC));
 3)如何下载图片并合成
    队列组|栅栏函数
 4)GCD补充知识
    (1)使用函数封装任务
      //异步函数,该方法使用函数来封装任务
                 dispatch_async_f(dispatch_queue_t queue, void *context, dispatch_function_t work)
           -(void)test{dispatch_async_f(dispatch_get_global_queue(0, 0), NULL(传给要调用函数的参数 可以不传), task);}
      void task (void *param){ NSLog(@"1----%@",[NSThread currentThread]); }
    (2)全局并发队列和create创建并发队列的区别
    (3)GCD对象的释放(iOS6.0之后不再需要手动释放)
    dispatch_queue_t queue = dispatch_queue_create("key", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, queue, ^{
        dispatch_group_enter(group);
        if(success){
            dispatch_group_leave(group);
        }
    });
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    });
    
    dispatch_queue_t queue = dispatch_queue_create("key", DISPATCH_QUEUE_SERIAL);
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, queue, ^{
        dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
        if(success){
            dispatch_semaphore_signal(semaphore);
        }
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    });
    dispatch_group_notify(group, queue, ^{
    });

\color{rgb(0 ,139, 139)}{}``


\color{rgb(0 ,139, 139)}{}``


\color{rgb(0 ,139, 139)}{}``


\color{rgb(0 ,139, 139)}{}``


\color{rgb(0 ,139, 139)}{}``


相关文章

  • iOS多线程:『GCD』详尽总结

    iOS多线程:『GCD』详尽总结 iOS多线程:『GCD』详尽总结

  • iOS多线程(一)-GCD

    iOS多线程-GCD

  • iOS多线程相关面试题

    iOS多线程demo iOS多线程之--NSThread iOS多线程之--GCD详解 iOS多线程之--NSOp...

  • 多线程之--NSOperation

    iOS多线程demo iOS多线程之--NSThread iOS多线程之--GCD详解 iOS多线程之--NSOp...

  • iOS多线程之--NSThread

    iOS多线程demo iOS多线程之--NSThread iOS多线程之--GCD详解 iOS多线程之--NSOp...

  • [iOS 多线程] iOS多线程-GCD

    iOS多线程-GCD GCD的简介 GCD,全称为 Grand Central Dispatch ,是iOS用来管...

  • iOS 多线程

    iOS 多线程有几种方式 GCD NSOpeartion NSThread phread 多线程 GCD disp...

  • GCD练习

    GCD练习 ios 多线程 GCD : ios 多线程 全剧队列,异步执行 线程间通信 信号量 文件锁 单利模式 ...

  • iOS开发多线程之GCD

    iOS开发多线程之GCDiOS开发之GCD同步任务加强iOS开发之GCD串行队列iOS开发之GCD并发队列 GCD...

  • iOS 多线程

    参考链接 iOS多线程iOS 多线程:『GCD』详尽总结iOS简单优雅的实现复杂情况下的串行需求(各种锁、GCD ...

网友评论

      本文标题:iOS 多线程 GCD

      本文链接:https://www.haomeiwen.com/subject/fhalgktx.html