iOS多线程-GCD

进程与线程

进程比作是一个电子厂,那么线程就是一条条的流水作业线。电子厂与电子厂之间相互独立,当前电子厂的作业流水线只能使用自己电子厂资源。

1.进程
  • 进程是指在系统中正在运行的一个应用程序,比如打开的Xcode
  • 每个进程之间是独立的,每个进程运行在专有的而且受保护的内存空间中。
2.线程
  • 线程是进程的基本执行单元,一个进程的所有任务都在线程中执行。
  • 进程想要执行任务,必须要有线程,进程至少要有一条线程用来执行任务。
  • 程序启动时会默认开启一条线程,这条线程被称为主线程或者UI线程。
3.线程和进程之间的关系
  • 线程是进程的执行单元,进程的所有任务都在线程中执行,同一个进程内的线程共享进程资源。
  • 地址空间:同一进程的线程共享本进程的地址空间,而进程之间则是独立的地址空间。
  • 资源拥有:同一进程内的线程共享本进程的资源如内存、I/Ocpu等,但是进程之间的 资源是独立的。
  • 一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉。所以多进程要比多线程健壮。
  • 进程切换时,消耗的资源大,效率高。所以涉及到频繁的切换时,使用线程要好于进程。同样如果要求同时进行并且又要共享某些变量的并发操作,只能用线程不能用进程。
  • 执行过程:每个独立的进程有一个程序运行的入口、顺序执行序列和程序入口。但是 线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
  • 线程是处理器调度的基本单位,但是进程是资源分配的基本单位。
  • 线程没有地址空间,线程包含在进程地址空间中。
4.多线程原理

一个进程可以开启多个线程,进程的所有任务都在线程中执行,而一个线程中的任务是串行的,如果要在一个线程中执行多个任务,那么只能一个一个地按顺序执行这些任务,也就是说,在同一时间内,一个线程只能执行一个任务,而在同一时刻,一个CPU只能处理一条线程(只有一个线程在执行任务),但CPU可以在多条线程之间快速的切换,只要切换的足够快,就造成了多线程一同执行的假象。

多线程的优缺点

优点

  • 能适当提高程序的执行效率
  • 能适当提高资源的利用率(CPU,内存)
  • 线程上的任务执行完成后,线程会自动销毁

缺点

  • 开启线程需要占用一定的内存空间(默认情况下,主线程占用1 MB,子线程都占用512 KB)
  • 如果开启大量的线程,会占用大量的内存空间,降低程序的性能
  • 线程越多,CPU在调用线程上的开销就越大
  • 程序设计更加复杂,比如线程间的通信、多线程的数据共享
5.UI主线程

一个iOS程序运行后,默认会开启一条线程,称为主线程UI线程.主线程主要用于显示刷新UI界面,处理UI事件。(最好不要将耗时任务放在主线程处理,耗时操作会卡住主线程,造成一种卡顿现象。)

6.线程的生命周期

image.png

  • 新建:实例化线程对象
  • 就绪:向线程对象发送start消息,线程对象并不会立即执行,线程对象被加入可调度线程池等待CPU调度。
  • 运行:CPU 负责调度可调度线程池中线程的执行。线程执行完成之前,状态可能会在就绪和运行之间来回切换。就绪和运行之间的状态变化由CPU负责,程序员不能干预。
  • 阻塞:当满足某个预定条件时,可以使用休眠或锁,阻塞线程执行。当进入休眠时,会重新将线程加入就绪状态中。休眠的时间设置参数为:sleepForTimeInterval(休眠指定时长),sleepUntilDate(休眠到指定日期),@synchronized(self):(互斥锁)。
  • 死亡:正常死亡,线程执行完毕。非正常死亡,当满足某个条件后,在线程内部中止执行(或者在主线程中止线程对象)
7.线程间通信

在苹果的文档Threading Programming Guide文档的Table 1-3 Communication mechanisms部分,有提到关于线程之间通信的方式。

截屏2021-06-18 下午2.16.46.png

8.多线程的实现方式

多线程的四种实现方式分别是:pthreadNSThreadGCDNSOperationimage.png

讲解常用实现方式GCD

GCD是苹果公司为多核的并行运算提出的解决方案,异步执行任务的技术之一。GCD 会自动利用更多的CPU内核,GCD会自动创建线程、调度任务、销毁线程 即会自动管理线程的生命周期。开发者只需要定义想要执行的任务,并告诉GCD想要执行的任务,不需要编写任何线程管理代码,GCD就能生成必要的线程并计划执行任务。

在了解GCD之前,先来了解几个概念:

  • 任务:就是将要在线程中执行的代码,将这段代码用block封装好,然后将这个任务添加到指定的执行方式(同步执行和异步执行),等待CPU从队列(串行队列和并发队列)中取出任务放到对应的线程中执行。
  • 队列:存放线程任务的队形结构。(系统以FIFO的方式调度队列中的任务进行执行),在GCD中有两种队列:串行队列和并发队列。
  • 同步执行:在某个线程中,任务会一个接着一个执行,前一个没有执行完,后面不能执行。
  • 异步执行:程序会开启多个新线程,任务同一时间可以一起执行。
  • 串行队列:线程任务依照队列中的顺序依次执行。
  • 并发队列:线程任务可以同时一起执行。

一句话概括,将任务添加到队列,并且指定执行任务的函数。这是使用GCD的核心思想。

这句话涉及任务队列函数三个概念:

  • 任务:就是block块内的代码,要被执行的部分
  • 队列:执行任务的等待队列,即用来存放任务的队列
  • 函数:是否可以在新的线程中执行任务,是否具备开启新线程的能力

img

不过一般合并表示:

dispatch_async(dispatch_queue_create("com.juejin.cn", NULL), ^{
    NSLog(@"hello word");
});

① dispatch_block_t 创建任务
② dispatch_queue_t 将任务添加到队列
③ dispatch_async 指定执行任务的函数

(1) 队列和函数

串行队列(Serial)

  • 不开辟新线程,每次只有一个任务被执行,任务一个接着一个地执行。

img

并发队列(Concurrent)

  • 可以开启多个线程,让多个任务并发(同时)执行。

img

主队列(Main)

  • 在主线程执行任务的队列,代码默认都被添加到主队列

  • 本质上是串行队列

  • 通常是返回主线程更新UI的时候会进行调用。

    全局队列(Global)

  • 系统自身使用的队列,如果对队列没有特殊要求,在执行异步任务时,可以借用

  • 本质上是并发队列

    同步函数(sync)

  • 同步添加任务到指定的队列中,在添加的任务执行结束之前,会一直等待,直到队列里面的任务完成之后再继续执行

  • 只能在当前线程中执行任务,不具备开启新线程的能力

    异步函数(async)

  • 异步添加任务到指定的队列中,不做任何等待,可以继续执行任务

  • 可以在新的线程中执行任务,具备开启新线程的能力

(2) 函数+队列

同步函数 + 串行队列

- (void)viewDidLoad {
    [super viewDidLoad];
    //**同步函数 + 串行队列**
    dispatch_queue_t queue = dispatch_queue_create("serial_queue", DISPATCH_QUEUE_SERIAL);
    for (int i = 0; i<2; i++) {
        dispatch_sync(queue, ^{
            NSLog(@"串行同步1-%d-%@",i,[NSThread currentThread]);
        });
    }
    for (int i = 0; i<2; i++) {
        dispatch_sync(queue, ^{
            NSLog(@"串行同步2-%d-%@",i,[NSThread currentThread]);
        });
    }
}

执行结果:

2021-11-22 13:44:04.579773+0800 GCD[8436:176549] <_NSMainThread: 0x600001018a00>{number = 1, name = main}

2021-11-22 13:44:04.580715+0800 GCD[8436:176549] 串行同步1-0-<_NSMainThread: 0x600001018a00>{number = 1, name = main}

2021-11-22 13:44:04.580782+0800 GCD[8436:176549] 串行同步1-1-<_NSMainThread: 0x600001018a00>{number = 1, name = main}

2021-11-22 13:44:04.580878+0800 GCD[8436:176549] 串行同步2-0-<_NSMainThread: 0x600001018a00>{number = 1, name = main}

2021-11-22 13:44:04.580952+0800 GCD[8436:176549] 串行同步2-1-<_NSMainThread: 0x600001018a00>{number = 1, name = main}

任务在当前线程下按照顺序执行,不会开启新线程;

同步函数 + 并发队列

    //**同步函数 + 并发队列**
    dispatch_queue_t queue = dispatch_queue_create("concurrent_queue", DISPATCH_QUEUE_CONCURRENT);
    for(int i = 0;i<2;++i)
    {
        dispatch_sync(queue, ^{
            NSLog(@"并发同步1-%d-%@",i,[NSThread currentThread]);
        });
    }
    for(int i = 0;i<2;++i)
    {
        dispatch_sync(queue, ^{
            NSLog(@"并发同步2-%d-%@",i,[NSThread currentThread]);
        });
    }

执行结果:

2021-11-22 13:44:37.431371+0800 GCD[8452:177308] <_NSMainThread: 0x60000246c1c0>{number = 1, name = main}

2021-11-22 13:44:37.431828+0800 GCD[8452:177308] 并发同步1-0-<_NSMainThread: 0x60000246c1c0>{number = 1, name = main}

2021-11-22 13:44:37.431892+0800 GCD[8452:177308] 并发同步1-1-<_NSMainThread: 0x60000246c1c0>{number = 1, name = main}

2021-11-22 13:44:37.431954+0800 GCD[8452:177308] 并发同步2-0-<_NSMainThread: 0x60000246c1c0>{number = 1, name = main}

2021-11-22 13:44:37.431996+0800 GCD[8452:177308] 并发同步2-1-<_NSMainThread: 0x60000246c1c0>{number = 1, name = main}

不会开启新线程,在当前线程下按顺序执行任务;

异步函数 + 串行队列

    //**异步函数 + 串行队列**
    NSLog(@"%@",[NSThread currentThread]);
    dispatch_queue_t queue = dispatch_queue_create("concurrent_queue", DISPATCH_QUEUE_SERIAL);
    for(int i = 0;i<2;++i)
    {
        dispatch_async(queue, ^{
            NSLog(@"串行异步1-%d-%@",i,[NSThread currentThread]);
        });
    }
    for(int i = 0;i<2;++i)
    {
        dispatch_async(queue, ^{
            NSLog(@"串行异步2-%d-%@",i,[NSThread currentThread]);
        });
    }

2021-11-22 13:50:47.072853+0800 GCD[8585:182927] <_NSMainThread: 0x600003944880>{number = 1, name = main}

2021-11-22 13:50:47.073698+0800 GCD[8585:183178] 串行异步1-0-<NSThread: 0x60000390e500>{number = 6, name = (null)}

2021-11-22 13:50:47.073872+0800 GCD[8585:183178] 串行异步1-1-<NSThread: 0x60000390e500>{number = 6, name = (null)}

2021-11-22 13:50:47.073975+0800 GCD[8585:183178] 串行异步2-0-<NSThread: 0x60000390e500>{number = 6, name = (null)}

2021-11-22 13:50:47.074040+0800 GCD[8585:183178] 串行异步2-1-<NSThread: 0x60000390e500>{number = 6, name = (null)}

会开启一个新线程,并在当前线程下,按照顺序执行任务;

异步函数 + 并发队列

        NSLog(@"%@",[NSThread currentThread]);
        dispatch_queue_t queue = dispatch_queue_create("concurrent_queue", DISPATCH_QUEUE_SERIAL);
        for(int i = 0;i<2;++i)
        {
            dispatch_async(queue, ^{
                NSLog(@"串行异步1-%d-%@",i,[NSThread currentThread]);
            });
        }
        for(int i = 0;i<2;++i)
        {
            dispatch_async(queue, ^{
                NSLog(@"串行异步2-%d-%@",i,[NSThread currentThread]);
            });
        }

2021-11-22 13:54:27.213033+0800 GCD[8662:186131] <_NSMainThread: 0x600001f807c0>{number = 1, name = main}

2021-11-22 13:54:27.214747+0800 GCD[8662:186327] 并行异步2-1-<NSThread: 0x600001f8ab80>{number = 4, name = (null)}

2021-11-22 13:54:27.214843+0800 GCD[8662:186314] 并行异步1-0-<NSThread: 0x600001fc2f40>{number = 6, name = (null)}

2021-11-22 13:54:27.214935+0800 GCD[8662:186315] 并行异步1-1-<NSThread: 0x600001fd9140>{number = 5, name = (null)}

2021-11-22 13:54:27.214970+0800 GCD[8662:186322] 并行异步2-0-<NSThread: 0x600001fd1980>{number = 7, name = (null)}

会开启新的线程,任务无顺序交替执行;

同步函数 + 主队列

    NSLog(@"%@",[NSThread currentThread]);
    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_sync(queue, ^{
        for(int i=0;i<2;i++){
            NSLog(@"主队列同步1-%d-%@",i,[NSThread currentThread]);
        }
    });
    NSLog(@"---%@",[NSThread currentThread]);

Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) 程序崩溃,任务互相等待,造成死锁。

形成死锁的原因:因为主队列依靠主线程,所以所有的任务都在主线程中执行,首先是一个NSLog打印任务,然后是block同步任务,同步任务里面也是NSLog打印任务,所以任务在队列中的顺序是:NSLog任务1->block任务->NSLog任务2,而此时因为是同步队列,block任务需要等NSLog任务2执行完,而NSLog任务2又需要等block任务执行完,这就形成了任务互相等待,形成死锁。

异步函数 + 主队列

    NSLog(@"%@",[NSThread currentThread]);
    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_async(queue, ^{
        for(int i=0;i<2;i++){
            NSLog(@"主队列异步1-%d-%@",i,[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for(int i=0;i<2;i++){
            NSLog(@"主队列异步2-%d-%@",i,[NSThread currentThread]);
        }
    });

2021-11-22 14:07:38.501634+0800 GCD[8930:196347] <_NSMainThread: 0x600003518880>{number = 1, name = main}

2021-11-22 14:07:38.609784+0800 GCD[8930:196347] 主队列异步1-0-<_NSMainThread: 0x600003518880>{number = 1, name = main}

2021-11-22 14:07:38.609903+0800 GCD[8930:196347] 主队列异步1-1-<_NSMainThread: 0x600003518880>{number = 1, name = main}

2021-11-22 14:07:38.610252+0800 GCD[8930:196347] 主队列异步2-0-<_NSMainThread: 0x600003518880>{number = 1, name = main}

2021-11-22 14:07:38.610358+0800 GCD[8930:196347] 主队列异步2-1-<_NSMainThread: 0x600003518880>{number = 1, name = main}

不会开启新线程,在主线程中串行执行任务。

image.png

GCD中的常用API

1.栅栏函数:dispatch_barrier_async

有时需要异步执行两个任务,而且第一个任务执行完之后,才能开始执行第二个任务。这样我们就需要一个相当于栅栏一样的一个方法将两个异步执行的任务给分开来,这就需要用到dispatch_barrier_async方法在两个任务值间形成栅栏。

    dispatch_queue_t queue = dispatch_queue_create("concurrent.queue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"1---%@",[NSThread currentThread]);
        }
    });
		//栅栏函数
    dispatch_barrier_async(queue, ^{
        [NSThread sleepForTimeInterval:5];
        NSLog(@"barrier---%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"2---%@",[NSThread currentThread]);
        }
    });

2021-11-22 14:24:53.513507+0800 GCD[9283:207839] 1—<NSThread: 0x600000647140>{number = 6, name = (null)}

2021-11-22 14:24:53.514711+0800 GCD[9283:207839] 1—<NSThread: 0x600000647140>{number = 6, name = (null)}

2021-11-22 14:24:58.520417+0800 GCD[9283:207839] barrier—<NSThread: 0x600000647140>{number = 6, name = (null)}

2021-11-22 14:24:58.520683+0800 GCD[9283:207839] 2—<NSThread: 0x600000647140>{number = 6, name = (null)}

2021-11-22 14:24:58.520769+0800 GCD[9283:207839] 2—<NSThread: 0x600000647140>{number = 6, name = (null)}

2.一次性方法:dispatch_once

    static dispatch_once_t onceToken;    
    dispatch_once(&onceToken, ^{        
    		//执行代码    
    });       
    dispatch_once保证了在运行期间,block中的代码只执行一次,block中的代码默认是线程安全的,适用于单利模式。

3.延时执行方法:dispatch_after

    NSLog(@"%@",[NSThread currentThread]);   
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)),  
    dispatch_get_main_queue(), ^{       
      // 2.0秒后异步追加任务代码到主队列,并开始执行        
      NSLog(@"after---%@",[NSThread currentThread]);   
    });

2021-11-22 14:39:05.537183+0800 GCD[9542:217083] <_NSMainThread: 0x600002d3c180>{number = 1, name = main}

2021-11-22 14:39:07.732290+0800 GCD[9542:217083] after—<_NSMainThread: 0x600002d3c180>{number = 1, name = main}

4.计时方法:dispatch_source_t

主要用于计时操作,其原因是因为它创建的timer不依赖于RunLoop,且计时精准度比NSTimer高。

    NSLog(@"%@",[NSThread currentThread]);
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    dispatch_source_set_timer(self.timer, DISPATCH_TIME_NOW, 3.0*NSEC_PER_SEC, 0.1*NSEC_PER_SEC);
    dispatch_source_set_event_handler(self.timer, ^{
        NSLog(@"%@",[NSThread currentThread]);
    });
    dispatch_resume(self.timer);

5.快速迭代方法:dispatch_apply

dispatch_apply按照指定的次数将指定的任务追加到指定的队列中,并等待全部队列执行结束。无论是在串行队列,还是异步队列中,dispatch_apply都会等待全部任务执行完毕,类似于同步执行。

 	 NSLog(@"%@",[NSThread currentThread]);   
     dispatch_queue_t queue = dispatch_queue_create("serial.queue", DISPATCH_QUEUE_SERIAL);    
     dispatch_apply(3, queue, ^(size_t index) {     
        NSLog(@"dispatch_apply--%ld--%@",index, [NSThread currentThread]); 
     });   
     NSLog(@"%@",[NSThread currentThread]);

2021-11-22 14:51:18.084649+0800 GCD[9808:227448] <_NSMainThread: 0x600003a80940>{number = 1, name = main}

2021-11-22 14:51:18.085282+0800 GCD[9808:227448] dispatch_apply–0--<_NSMainThread: 0x600003a80940>{number = 1, name = main}

2021-11-22 14:51:18.085366+0800 GCD[9808:227448] dispatch_apply–1--<_NSMainThread: 0x600003a80940>{number = 1, name = main}

2021-11-22 14:51:18.085443+0800 GCD[9808:227448] dispatch_apply–2--<_NSMainThread: 0x600003a80940>{number = 1, name = main}

2021-11-22 14:51:18.085509+0800 GCD[9808:227448] dispatch_apply–3--<_NSMainThread: 0x600003a80940>{number = 1, name = main}

2021-11-22 14:51:18.085598+0800 GCD[9808:227448] dispatch_apply–4--<_NSMainThread: 0x600003a80940>{number = 1, name = main}

2021-11-22 14:51:18.085656+0800 GCD[9808:227448] <_NSMainThread: 0x600003a80940>{number = 1, name = main}

6.监听任务方法:dispatch_group_notify

    NSLog(@"0---%@",[NSThread currentThread]);    
    dispatch_group_t group =  dispatch_group_create();    
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
    ^{        
    	NSLog(@"1---%@",[NSThread currentThread]);   
     });   
     dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{       
     NSLog(@"2---%@",[NSThread currentThread]);   
      });  
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{      
      // 等前面的异步任务1、任务2都执行完毕后,回到主线程执行任务        
      NSLog(@"3---%@",[NSThread currentThread]);    
     });

2021-11-22 14:55:10.441718+0800 GCD[9910:232011] 0—<_NSMainThread: 0x600000828000>{number = 1, name = main}

2021-11-22 14:55:10.443018+0800 GCD[9910:232244] 2—<NSThread: 0x600000821fc0>{number = 6, name = (null)}

2021-11-22 14:55:10.443104+0800 GCD[9910:232248] 1—<NSThread: 0x6000008664c0>{number = 3, name = (null)}

2021-11-22 14:55:10.547045+0800 GCD[9910:232011] 3—<_NSMainThread: 0x600000828000>{number = 1, name = main}

7.阻塞线程:dispatch_group_wait

阻塞当前线程,等待group中的任务执行完成后,才会往下继续执行任务。

      NSLog(@"0---%@",[NSThread currentThread]);  
      dispatch_group_t group =  dispatch_group_create();    
      dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{       
       [NSThread sleepForTimeInterval:2];        
      	    NSLog(@"1---%@",[NSThread currentThread]); 
      });   
      dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{        
      		NSLog(@"2---%@",[NSThread currentThread]);    
      });   
      dispatch_group_wait(group, DISPATCH_TIME_FOREVER);    
      NSLog(@"0---%@",[NSThread currentThread]);

2021-11-22 15:11:41.771840+0800 GCD[10220:242409] 0—<_NSMainThread: 0x6000032ac140>{number = 1, name = main}

2021-11-22 15:11:41.773034+0800 GCD[10220:242653] 2—<NSThread: 0x6000032fa500>{number = 6, name = (null)}

2021-11-22 15:11:43.778294+0800 GCD[10220:242657] 1—<NSThread: 0x6000032929c0>{number = 3, name = (null)}

2021-11-22 15:11:43.778572+0800 GCD[10220:242409] 0—<_NSMainThread: 0x6000032ac140>{number = 1, name = main}

8.dispatch_group_enterdispatch_group_leave

dispatch_group_enter表示一个任务追加到指定的groupdispatch_group_leave表示一个任务离开了指定的group

    NSLog(@"%@",[NSThread currentThread]);
    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
        NSLog(@"1---%@",[NSThread currentThread]);
        dispatch_group_leave(group);
    });
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
        NSLog(@"2---%@",[NSThread currentThread]);
        dispatch_group_leave(group);
    });
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"3---%@",[NSThread currentThread]);
    });
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);

    NSLog(@"%@",[NSThread currentThread]);

021-11-22 15:45:26.662907+0800 GCD[10871:262130] <_NSMainThread: 0x600003edc200>{number = 1, name = main}

2021-11-22 15:45:38.587724+0800 GCD[10871:262380] 1—<NSThread: 0x600003ede500>{number = 6, name = (null)}

2021-11-22 15:45:45.979552+0800 GCD[10871:262381] 2—<NSThread: 0x600003e8a880>{number = 7, name = (null)}

2021-11-22 15:45:54.710573+0800 GCD[10871:262130] <_NSMainThread: 0x600003edc200>{number = 1, name = main}

2021-11-22 15:45:58.374207+0800 GCD[10871:262130] 3—<_NSMainThread: 0x600003edc200>{number = 1, name = main}

9.信号量:dispatch_semaphore_t

信号量是一种同步锁,主要用于控制最大并发数,可以将异步执行任务转换为同步执行任务。

    NSLog(@"-----%@",[NSThread currentThread]);
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    for (int i = 0; i < 5; i++) {
        dispatch_async(queue, ^{
            NSLog(@"信号量:%d------%@", i, [NSThread currentThread]);
            dispatch_semaphore_signal(semaphore);
        });
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    }
    NSLog(@"-----%@",[NSThread currentThread]);
  1. dispatch_semaphore_create():创建信号量
  2. dispatch_semaphore_wait():等待信号量,调用一次,信号量减1。当信号量<0时会阻塞当前线程,根据传入的时间参数决定接下来的任务执行,如果时间参数为永久等待,则将等到有信号才继续执行下去。
  3. dispatch_semaphore_signal():释放信号量,调用一次,信号量加1。当信号量>=0会执行dispatch_semaphore_wait之后的代码。

2021-11-22 16:17:26.884311+0800 GCD[11491:282599] -----<_NSMainThread: 0x6000003ec7c0>{number = 1, name = main}

2021-11-22 16:17:30.148382+0800 GCD[11491:282767] 信号量:0------<NSThread: 0x6000003eaf00>{number = 3, name = (null)}

2021-11-22 16:19:29.918522+0800 GCD[11491:282767] 信号量:1------<NSThread: 0x6000003eaf00>{number = 3, name = (null)}

2021-11-22 16:19:32.850850+0800 GCD[11491:282768] 信号量:2------<NSThread: 0x6000003e7100>{number = 5, name = (null)}

2021-11-22 16:19:35.136345+0800 GCD[11491:282767] 信号量:3------<NSThread: 0x6000003eaf00>{number = 3, name = (null)}

2021-11-22 16:19:36.210910+0800 GCD[11491:282768] 信号量:4------<NSThread: 0x6000003e7100>{number = 5, name = (null)}

2021-11-22 16:19:36.950593+0800 GCD[11491:282599] -----<_NSMainThread: 0x6000003ec7c0>{number = 1, name = main}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值