iOS 多线程

iOS多线程---GCD方法/实现Timer

2016-06-28  本文已影响1326人  simuty

多线程核心概念: 一个任务 / 两种队列 / 两种函数.


1. 一个任务: 执行什么操作;
2. 执行任务的两种队列: 
(1)并发队列(Concurrent Dispatch Queue): 可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务), 
前提是在dispatch_async异步函数下执行; 
(2)串行队列(Serial Dispatch Queue):一个任务执行完毕后,再执行下一个任务.

2.1 并发队列和串行队列的区别: 任务的执行方式不同

---------------------------------------------------
3. 执行任务的两种函数:
(1)同步函数dispatch_sync  < synchronous>: 不具备开启新线程的能力; 
(2)异步函数dispatch_async <asynchronous>: 具备开启新线程的能力

3.1 同步和异步区别:能不能开启新的线程



多线程创建队列的两种方式


1. 通过dispatch_queue_create函数创建一个队列;
2. 直接获取现成的主线程dispatch队列或者全局的dispatch队列。




Paste_Image.png



GCD实现的Timer如图所示:

Paste_Image.png

核心代码:


//开始
- (IBAction)startTimer:(id)sender {
 __block int startTimer = 0;
    __weak typeof(self) weakself = self;
    
    //开启专门的线程处理timer
    self.timerQueue = dispatch_queue_create("TimerQueue", 0);
    self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, _timerQueue);
    /*----打出dispatch_s直接就出现下边的代码块了---------*/
    /**
     *  第一个参数: dispatch_source_t, Dispatch Source
     *  第二个参数: 开始时刻;
     *  第三个参数: 间隔<例子中是一秒>;
     *  第四个参数: 精度<最高精度将之设置为0>
     */
    dispatch_source_set_timer(self.timer, DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
    //函数回调
    dispatch_source_set_event_handler(self.timer, ^{
        //回主线刷新UI
        dispatch_async(dispatch_get_main_queue(), ^{
            weakself.label.text = [NSString stringWithFormat:@"%d", startTimer++];
        });
    });
    //默认的dispatch_source_t是暂停, 开始监听
    dispatch_resume(self.timer);
    /*----打出dispatch_s直接就出现上边的代码块了---------*/
    
}

dispatch_queue_create创建两种队列


//创建一个串行dispatch队列, 第二个参数将其设置成NULL。
dispatch_queue_t mySerialDispatchQueue =
    dispatch_queue_create("com.example.gcd", NULL);

//创建一个串行dispatch队列, 第二个参数就设置成DISPATCH_QUEUE_CONCURRENT
dispatch_queue_t myConcurrentDispatchQueue =
    dispatch_queue_create( "com.example.gcd.MyConcurrentDispatchQueue", DISPATCH_QUEUE_CONCURRENT);


具体操作

1.直接获取线程的队列


1. 主线程dispatch队列: 所有任务都在主线程上执行, 它是一个串行队列。

dispatch_queue_t mainDispatchQueue = dispatch_get_main_queue();

--------------------------------------------------


2. 全局的dispatch队列: 它是并行队列,可以在应用程序的任何地方使用它们。
一般可以直接使用该队列. 有四种优先级:high, default, low 和 background。


dispatch_queue_t globalDispatchQueueDefault =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);


2. dispatch_set_target_queue 设置优先级

dispatch_set_target_queue函数用于设置一个”目标”队列。创建队列后,你可以用这个函数来修改队列的优先级。

3. dispatch_group_async 分组

等dispatch队列中的所有任务完成了才执行另外一个任务。
dispatch_group_async就可以上场了.

4. dispatch_barrier_async 栅栏方式

dispatch_barrier_async函数用于等待队列中其他任务完成。
1. 当你访问数据库或者一个文件的时候,你可以用串行队列来避免数据冲突。
2. 多个读取操作是可以同时进行的,这样可以更高效的访问数据,但更新数据时必须等其他操作结束, 如果使用前两种方式会很麻烦.
3. dispatch_barrier_async 创建了一个并发队列,然后向队列中添加了一些读取操作。会等本次操作以前的完全执行才执行.


5. dispatch_apply

dispatch_apply函数会像dispatch_sync函数一样等待所有任务完成,

//串行队列是有序的
    dispatch_apply(5, syncQueue, ^(size_t index) {
        NSLog(@"++++++ %zu", index);
    });
    
    顺序: 01234


//并发队列是无序
    dispatch_apply(5, asyncQueue, ^(size_t index) {
        NSLog(@"----%zu", index);
    });
    
    顺序不固定




6. dispatch_semaphore_t 信号量

并发读取或更新数据时很容易造成数据冲突或者程序崩溃。
当你需要对一小部分间隔时间较短的任务做并发控制的时候,Semaphore(信号量)会比串行队列或者dispatch_barrier_async更好用。

Dispatch semaphore是一个带有一个计数器的信号量。信号量有点像一个交通信号标志,标志起来的时候你
可以走,标准落下的时候你要停下来。Dispatch semaphore用计数器来模拟这种标志。计数器为0,队列暂停
执行新任务并等待信号;当计数器超过0后,队列继续执行新任务,并减少计数器。
//用dispatch_semaphore_create函数。
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
//dispatch_semaphore_wait函数用于等待一个信号量。
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 1ull * NSEC_PER_SEC);

long result = dispatch_semaphore_wait(semaphore, time);
if (result == 0){
/*
 * 信号量计数器大于等于1。
 * 或者在指定的等待时间超时前,信号量计数器变成了大于等于1的数字。
 * 计数器会自动减一
 *
 * 在这里,可以安全地运行你的任务了。
 */
}else{
/*
 * 因为信号量计数器是0,就只能等待超时了。
 * 
 * 这里处理等待超时的情况。
 */
}

GCD支持方法示例代码
GCD实现的Timer代码

GCD使用详解

更多精彩内容请关注“IT实战联盟”哦~~~


IT实战联盟.jpg
上一篇下一篇

猜你喜欢

热点阅读