iOS:常驻线程

常驻线程

在实际的项目中,根据需求咱们可能须要在后台常驻一个线程作一些事情。而对于常驻线程搜索下的话会有不少解决方案,可是大多数都是提到使用NSThreadRunLoop来实现的。而在本篇中介绍另一种实现方法,那就是采用信号量的方式来实现。什么是信号量?我这里简单的解释下objective-c

信号量主要是用在多线程的场景,一个线程等待信号直到接收到信号继续运行,另一个线程发送信号通知等待的线程继续运行。数组

信号量的运行方式正好跟咱们须要的常驻线程的需求是契合的。在没有任务的时候让该线程处于等待状态,等有任务了,那么发送一个信号让常驻线程执行咱们的任务。安全

下面是实现的代码:多线程

/**
 常驻线程
 */
@interface ResidentThread : NSObject
-(void)doAction:(dispatch_block_t)action;
-(void)cancel;
@end

@implementation ResidentThread{
    NSMutableArray *actions;
    NSThread *thread;
    dispatch_semaphore_t sem;
    bool cancel;
}
-(id)init{
    self = [super init];
    actions = [NSMutableArray array];
    // 建立信号量
    sem = dispatch_semaphore_create(0);
    // 建立一个新线程
    thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
    [thread start];
    return self;
}

-(void)run{
    while (true) {
        // 等待信号量
        dispatch_semaphore_wait(sem, -1);
        // 收到信号
        // 若是线程已经取消了,那么退出循环
        if(cancel){
            break;
        }
        // 开始执行任务
        dispatch_block_t block = [actions firstObject];
        if(block){
            [actions removeObject:block];
            block();
        }
        
    }
}

// 执行某个任务
-(void)doAction:(dispatch_block_t)action{
    if(!cancel){ // 若是线程已经cancel了,那么直接忽略
        // 将任务放入数组
        [actions addObject:[action copy]];
        // 发送信号
        dispatch_semaphore_signal(sem);
    }
}

// 终止常驻线程
-(void)cancel{
    cancel = YES;
    // 线程取消后,清空全部的回调
    [actions removeAllObjects];
    // 至关于发送一个终止任务的信号
    dispatch_semaphore_signal(sem);
}
@end

复制代码

上面代码中使用了GCD的信号量,原本想使用semaphore.h头文件中的信号量API的,可是这里面的API已经被苹果DEPRECATED了,就算你强制使用,那么也没法初始化信号量。ide

下面分析代码: ResidentThread对外总共提供了两个方法,分别是doAction:canceloop

  1. doAction::这个方法接收一个dispatch_block_t的参数,表明实际须要让常驻线程执行的任务。
  2. cancel:终止该常驻线程。

    为了安全起见,这里采用的是标记位的方式。另外要注意到,cancel方法里面额外发送了一个信号,这个信号的做用相似于发送了一个终止任务的信号spa

从上面的代码中能够看出,常驻线程的原理是很简单的,并且在实现上也很简单。而且你会发现,这里面的任务实际上是串行执行的。线程

Runloop

Runloop的原理我就很少介绍了,掘金里面有不少分析文章,讲的也很透彻,甚至有些直接把源码都贴出来分析。code

从上面的常驻线程的代码中能够看出来,run方法的内部就是一个while循环,循环等待信号,当接收到信号后立马执行任务。执行完任务后继续等待信号。这样一个流程实际上是跟Runloop的工做原理是差很少的。Runloop也是一个等待信号>收到信号>执行回调>继续等待信号,这样一个流程。rem

事实上,这样一套代码,在其余语言中好比C、C++上差很少就是这样实现。

若是进一步的发散下呢?GCD的任务调度的实现是否是也相似这样呢?事实上,我曾今在写C的时候,就是使用上面的代码实现多线程的任务调度功能。

相关文章
相关标签/搜索