使用dispatch_group、dispatch_semaphore_t进行多线程管理

在日常工作过程中,经常会遇到多线程任务的情况,如果需要同时进行多个线程任务而APP又需要对多线程进行管理,那么就可以使用dispatch_group进行管理。

关于dispatch_group的使用这里就不多赘述了,网上也有很多相关的资料,这里讨论的是当有多个线程并发进行时,如何控制多线程的执行顺序让子线程能够按照我们所需要的进行按序处理?

请先看如下代码:

@interface ViewController ()

@property(nonatomic,strong) dispatch_group_t group_t;
@property(nonatomic,strong) dispatch_queue_t testQueue;

@end

@implementation ViewController

- (dispatch_group_t)group_t
{
   if (_group_t == nil) {
       _group_t = dispatch_group_create();
   }
   return _group_t;
}

- (dispatch_queue_t)testQueue
{
   if (_testQueue == nil) {
       _testQueue = dispatch_queue_create("com.suning.myTestQueue", DISPATCH_QUEUE_CONCURRENT);
   }
   return _testQueue;
}

- (void)viewDidLoad {
   [super viewDidLoad];
   
   [self testGroup];
   // Do any additional setup after loading the view, typically from a nib.
}

- (void)testGroup
{
   [self functionThree];
   [self functionTwo];
   [self functionOne];

   dispatch_group_notify(self.group_t, self.testQueue, ^{
       NSLog(@"finish!");
   });
}

- (void)functionOne
{
   dispatch_group_enter(self.group_t);
   dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
       NSLog(@"functionOne");
       sleep(2);
       NSLog(@"functionOne finish");
       dispatch_group_leave(self.group_t);
   });
}

- (void)functionTwo
{
   dispatch_group_enter(self.group_t);
   dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
       NSLog(@"functionTwo");
       sleep(4);
       NSLog(@"functionTwo finish");
       dispatch_group_leave(self.group_t);
   });
}

- (void)functionThree
{
   dispatch_group_enter(self.group_t);
   dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
       NSLog(@"functionThree");
       sleep(6);
       NSLog(@"functionThree finish");
       dispatch_group_leave(self.group_t);
   });
}

我们可以得出log日志:

2018-07-18 10:39:46.901024+0800 testaaa[2937:66818] functionOne
2018-07-18 10:39:46.901024+0800 testaaa[2937:66815] functionThree
2018-07-18 10:39:46.901024+0800 testaaa[2937:66817] functionTwo
2018-07-18 10:39:48.902328+0800 testaaa[2937:66818] functionOne finish
2018-07-18 10:39:50.902084+0800 testaaa[2937:66817] functionTwo finish
2018-07-18 10:39:52.902949+0800 testaaa[2937:66815] functionThree finish
2018-07-18 10:39:52.903199+0800 testaaa[2937:66815] finish!

从日志中我们可以清楚的看到,时间间隔为了2s、2s、2s,这说明4个函数确实是同步执行了。
但是从日志中可以看出,最后调用的functionOne因为耗时最短(2s)而最先完成任务,而最先调用的functionThree因为耗时最长(6s)最后才完成任务。如果在此前提下需要既异步执行任务,又要最先调用的函数最先完成任务,如何实现呢?
使用dispatch_group无法实现我们的需求。dispatch_group主要作用就是在多个线程处理完成后,执行dispatch_group_notify,通知开发者所有线程已经处理完毕,并不关心线程的先后调用顺序。
这里就引入了dispatch_semaphore_t信号量的概念。

定义:

1、信号量:就是一种可用来控制访问资源的数量的标识,设定了一个信号量,在线程访问之前,加上信号量的处理,则可告知系统按照我们指定的信号量数量来执行多个线程。

其实,这有点类似锁机制了,只不过信号量都是系统帮助我们处理了,我们只需要在执行线程之前,设定一个信号量值,并且在使用时,加上信号量处理方法就行了。

请看代码:

@interface ViewController ()

@property(nonatomic,strong) dispatch_queue_t testQueue;
@property(nonatomic,strong) dispatch_semaphore_t semaphore_t;

@end

@implementation ViewController

- (dispatch_queue_t)testQueue
{
    if (_testQueue == nil) {
        _testQueue = dispatch_queue_create("com.suning.myTestQueue", DISPATCH_QUEUE_CONCURRENT);
    }
    return _testQueue;
}

- (dispatch_semaphore_t)semaphore_t
{
    if (_semaphore_t == nil) {
        _semaphore_t = dispatch_semaphore_create(1);
    }
    return _semaphore_t;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self testSemaphore];
    
    // Do any additional setup after loading the view, typically from a nib.
}

- (void)testSemaphore
{
    dispatch_async(self.testQueue, ^{
        dispatch_semaphore_wait(self.semaphore_t, DISPATCH_TIME_FOREVER);
        NSLog(@"run task 1");
        sleep(6);
        NSLog(@"complete task 1");
        dispatch_semaphore_signal(self.semaphore_t);
    });
    
    dispatch_async(self.testQueue, ^{
        dispatch_semaphore_wait(self.semaphore_t, DISPATCH_TIME_FOREVER);
        NSLog(@"run task 2");
        sleep(4);
        NSLog(@"complete task 2");
        dispatch_semaphore_signal(self.semaphore_t);
    });

    dispatch_async(self.testQueue, ^{
        dispatch_semaphore_wait(self.semaphore_t, DISPATCH_TIME_FOREVER);
        NSLog(@"run task 3");
        sleep(2);
        NSLog(@"complete task 3");
        dispatch_semaphore_signal(self.semaphore_t);
    });
}

日志打印如下:

2018-07-18 10:36:19.457335+0800 testaaa[2854:64194] run task 1
2018-07-18 10:36:25.457796+0800 testaaa[2854:64194] complete task 1
2018-07-18 10:36:26.332852+0800 testaaa[2854:64193] run task 2
2018-07-18 10:36:30.335898+0800 testaaa[2854:64193] complete task 2
2018-07-18 10:36:31.308968+0800 testaaa[2854:64192] run task 3
2018-07-18 10:36:33.313752+0800 testaaa[2854:64192] complete task 3

可以看出在信号量的控制下,异步线程也能按序进行,基本达到了我们预先的目标

你可能感兴趣的:(使用dispatch_group、dispatch_semaphore_t进行多线程管理)