GCD 信号量

这种情况下,将所有的数据追加到NSMutableArray中。

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    NSMutableArray *array = [[NSMutableArray alloc]init];

    for (int i = 0; i < 100000; i++) {
        dispatch_async(queue, ^{

            [NSThread sleepForTimeInterval:3];
            NSLog(@"task %@ %d",[NSThread currentThread],i);

            [array addObject:[NSNumber numberWithInt:i]];

        });
    }
    

因为该代码使用Global 更新NSMutableArray 类对象,所以执行后由内存错误导至应用异常结束的概率很高。应使用Dispatch Semaphore。

Dispatch Semaphore 信号量是一个整形值并且具有一个初始计数值,并且支持两个操作:信号通知和等待。当一个信号量被信号通知,其计数会被增加。当一个线程在一个信号量上等待时,线程会被阻塞(如果有必要的话),直至计数器大于零,然后线程会减少这个计数。
  在GCD中有三个函数是semaphore的操作,分别是:
  dispatch_semaphore_create   创建一个semaphore
  dispatch_semaphore_signal   发送一个信号
  dispatch_semaphore_wait    等待信号
  简单的介绍一下这三个函数,第一个函数有一个整形的参数,我们可以理解为信号的总量,dispatch_semaphore_signal是发送一个信号,自然会让信号总量加1,dispatch_semaphore_wait等待信号,当信号总量少于0的时候就会一直等待,否则就可以正常的执行,并让信号总量-1,根据这样的原理,我们便可以快速的创建一个并发控制来同步任务和有限资源访问控制。

看代码

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    /**
     生成Dispatch semaphore
     Dispatch semaphore得计数初始值是 “1”
     保证可访问NSMutableArray 类对象的线程同时只能有6个
     */
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(6);

    NSMutableArray *array = [[NSMutableArray alloc]init];

    for (int i = 0; i < 100000; i++) {
        dispatch_async(queue, ^{

            /**
             等待直到Dispatch semaphore 计数值达到大于等于1
             */
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            [NSThread sleepForTimeInterval:3];
            NSLog(@"task %@ %d",[NSThread currentThread],i);

            [array addObject:[NSNumber numberWithInt:i]];

            /**
             线程结束的时候会发送一个信号
             */
            dispatch_semaphore_signal(semaphore);
        });
    }

创建了一个初使值为6的semaphore,每一次for循环都会创建一个新的线程,线程结束的时候会发送一个信号,线程创建之前会信号等待,所以当同时创建了6个线程之后,for循环就会阻塞,等待有线程结束之后会增加一个信号才继续执行,如此就形成了对并发的控制,如上就是一个并发数为6的一个线程队列。

时间: 2024-08-02 12:53:11

GCD 信号量的相关文章

用GCD线程组与GCD信号量将异步线程转换为同步线程

有时候我们会碰到这样子的一种情形: 同时获取两个网络请求的数据,但是网络请求是异步的,我们需要获取到两个网络请求的数据之后才能够进行下一步的操作,这个时候,就是线程组与信号量的用武之地了. 线程组用以监听线程的执行情况,而信号量就是用来将异步线程转化为同步线程. 以下是打印的数据: 2015-02-25 18:34:23.208 YXMWeather[265:8748] 请求1数据 2015-02-25 18:34:23.209 YXMWeather[265:8790] 1信号量结束 2015-

GCD信号量机制

1.创建信号量,创建的初始值决定线程并发数 dispatch_semaphore_t semaphore = dispatch_semaphore_create(2); 2.等待信号 dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); // 由于是异步执行的,所以每次循环Block里面的dispatch_semaphore_signal根本还没有执行就会执行dispatch_semaphore_wait,从而semaphore-1

IOS开发之多线程 -- GCD的方方面面

前言:这篇GCD的博文是本人阅读了很多海内外大神的关于GCD的文章,以及结合之前自己对GCD的粗浅的认识,然后取其精华,去其槽粕,综合起来的笔记,而且是尽可能的以通熟易懂的并且是正确的理论论述方式呈现给读者,同时也是讲大神博客中有的深涩的理论理解的通熟易懂转述给读者,已经是尽可能的让读者深入理解和掌握多线程的知识以及GCD的使用技术.最后的附录中,我将会给出所有本人阅读的大神写的关于多线程或者是GCD的文章链接,大家感兴趣的,可以去参考和学习.也许,看我的这篇就够了,因为我就是参考他们的,嘻嘻.

GCD实现同步方法

在iOS多线程中我们知道NSOperationQueue操作队列可以直接使用addDependency函数设置操作之间的依赖关系实现线程同步,还可以使用setMaxConcurrentOperationCount函数直接设置最大并发数量.那么在GCD中又是如何实现线程同步和控制最大并发数量的呢? 事实上在之前的问题中我们已经提到了GCD实现线程同步的两种方法了,一种是组队列(dispatch_group_t),另一种是dispatch_barrier_(a)sync,都是等待前面的任务完成后再执

再次学习GCD

在cocoachina上看到一篇文章,今天学下. 一.任务 任务:线程中那个执行的代码段. 执行任务分为两种: 1.sync(同步):等待队列的任务执行结束 dispatch_sync(dispatch_queue_t,^{ //执行代码 }); NSLog(@"hello,sync"); 直白说就是:代码自行到dispatch_sync(),会执行Block块---blockSync(形参), blockSync执行结束后,执行NSLog,输出hello,sync!!!! 2.asy

iOS 多线程:『GCD』详尽总结

本文用来介绍 iOS 多线程中 GCD 的相关知识以及使用方法.这大概是史上最详细.清晰的关于 GCD 的详细讲解+总结的文章了.通过本文,您将了解到: 1. GCD 简介 2. GCD 任务和队列 3. GCD 的使用步骤 4. GCD 的基本使用(6种不同组合区别) 5. GCD 线程间的通信 6. GCD 的其他方法(栅栏方法:dispatch_barrier_async.延时执行方法:dispatch_after.一次性代码(只执行一次):dispatch_once.快速迭代方法:dis

『GCD』详解

2. GCD 任务和队列 学习 GCD 之前,先来了解 GCD 中两个核心概念:任务和队列. 任务:就是执行操作的意思,换句话说就是你在线程中执行的那段代码.在 GCD 中是放在 block 中的.执行任务有两种方式:同步执行(sync)和异步执行(async).两者的主要区别是:是否等待队列的任务执行结束,以及是否具备开启新线程的能力. 同步执行(sync): 同步添加任务到指定的队列中,在添加的任务执行结束之前,会一直等待,直到队列里面的任务完成之后再继续执行. 只能在当前线程中执行任务,不

FMDB的线程安全

最近面试被问到FMDB的多线程处理问题,因为之前项目中是移植别人的代码,没有踩过这里的坑. 问题: 多线程同时访问数据库时,报数据库锁定的问题,错误信息是: Unknown error finalizing or resetting statement (5: database is locked) 原因: 文件数据库sqlite,同一时刻允许多个进程/线程读,但同一时刻只允许一个线程写.在操行写操作时,数据库文件被琐定,此时任何其他读/写操作都被阻塞,如果阻塞超过5秒钟(默认是5秒,能过重新编

[ios] ios6 ios7 访问和使用系统通讯录

导入AddressBook和AddressBookUI框架 iOS 6之前,可以通过如下方法获得通讯录 ABAddressBookRef addressBook = ABAddressBookCreate(); 不过在iOS 6之后,这个方法被废弃,可以使用下面的方法获得通讯录. AB_EXTERN ABAddressBookRef ABAddressBookCreateWithOptions(CFDictionaryRef options, CFErrorRef* error) __OSX_A