使用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

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

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 今天生理期,加之最近各种压力和不顺利,心情极其不佳。 昨天失眠几乎一夜没睡,白天强撑着完成了工作,还坚持着早起学习...
    张小团子阅读 162评论 0 0
  • 想象一幅这样的画面,温暖的被窝、冰冷的空气、窗外的阳光、树上的鸟鸣声、远方传来的炮鸣…… 再远点,有大片的田野、蜿...
    会飞的蠢猪阅读 243评论 0 0
  • 从孩子上高中到现在,给孩子说的最多的一句话就是,孩子你要坚持。让他坚持六点起床,让他坚持吃早餐,坚持少吃零食,坚持...
    北方人_4bf2阅读 258评论 0 1
  • 各位有更好的版本提供吗? 又一项学习计划提上日程,被很多病人说我开药方的字不够霸气,太小家子气[捂脸]看来得学学行...
    野生灵芝爱上优弹素阅读 182评论 0 0
  • 本宝为减肥可谓百招齐出。但最后都敌不过毅力跟口欲--→→看着自己的游泳圈越来越大,已经向外赶的趋势,我恨不得咬死它...
    上月玄阅读 288评论 0 0