GCD之信号量dispatch_semaphore

信号量是基于计数器的一种多线程同步机制,用来管理对资源的并发访问。
信号量内部有一个可以原子递增或递减的值。如果一个动作尝试减少信号量的值,使其小于0,那么这个动作将会被阻塞,直到有其他调用者(在其他线程中)增加该信号量的值。
信号量就是一种可用来控制访问资源的数量的标识,设定了一个信号量,在线程访问之前,加上信号量的处理,则可告知系统按照我们指定的信号量数量来执行多个线程。

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

简单来讲 信号量为0则阻塞线程,大于0则不会阻塞。则我们通过改变信号量的值,来控制是否阻塞线程,从而达到线程同步。

dispatch_semaphore相关的3个函数

  • dispatch_semaphore_create
    创建一个Semaphore并初始化信号的总量
/*!
 * @function dispatch_semaphore_create
 * @abstract 创建一个新的信号量
 * @param value 信号量的初始值,传入小于0的数返回NULL
 */
dispatch_semaphore_t
dispatch_semaphore_create(long value);
  • dispatch_semaphore_wait
    可以使总信号量减1,当信号总量为0时就会一直等待(阻塞所在线程),否则就可以正常执行。
/*!
 * @function dispatch_semaphore_wait
 *
 * @abstract 等待信号量
 * Wait (decrement) for a semaphore.
 * @param dsema 创建好的信号量
 * @param timeout 信号等待时间,一般使用DISPATCH_TIME_FOREVER,在得到signal之前一直等待
 */
dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);
  • dispatch_semaphore_signal
    发送一个信号,让信号总量加1
/*!
 * @function dispatch_semaphore_signal
 *
 * @abstract 提高信号量, 使信号量加1并返回
 * @param dsema 已创建好的信号
 */
dispatch_semaphore_signal(dispatch_semaphore_t dsema);

dispatch_semaphore主要应用于两个方面

  • 线程同步
    直接上代码
- (void)semaphoreTest {
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    __block long j = 0;
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i < 1000; i ++) {
            j ++;
        }
        dispatch_semaphore_signal(semaphore);
    });
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    NSLog(@"%ld",j);
}
//运行结果:2018-05-23 17:56:48.064 MultiThreadingDemo[2955:535470] 1000

代码说明:block块异步执行添加到了全局并发队列里,所以程序在主线程会跳过block块(同时开辟子线程异步执行block块),执行块外的代码dispatch_semaphore_wait,因为semaphore信号量为0,且时间为DISPATCH_TIME_FOREVER,所以会阻塞当前线程(主线程),进而只执行子线程的block块,直到执行块内部的dispatch_semaphore_signal使得信号量+1。正在被阻塞的线程(主线程)会恢复继续执行。这样保证了线程之间的同步。

  • 为线程加锁,限制并发线程数量
    使用dispatch_semaphore_create(0);保证在同一时间只有一个线程访问,实现加锁功能。关于限制线程数量,我们用一个停车场的demo看一下:
//停车场demo
- (void)parkingAreaADemo {
    //假设目前有3个停车位
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(3);
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    //有10辆车过来打算停车
    for (NSInteger i = 1; i <= 10; i ++) {
        dispatch_async(queue, ^{
            NSInteger carId = i;
            if (carId % 3 == 0) {
                //这几位车主不愿意一直等待,所有设定一个能接受的等待时间
                NSUInteger result = dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 8 * carId * NSEC_PER_SEC));
                if (result != 0) {//超时,直接离开
                    NSLog(@"第%ld个车主不等了",carId);
                } else {
                    NSLog(@"第%ld个车主在规定的时间内等到了车位,进入停车场",carId);
                    [NSThread sleepForTimeInterval:10];
                    dispatch_semaphore_signal(semaphore);
                    NSLog(@"第%ld个车主离开,有空位了",carId);
                }
            } else {
                dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
                NSLog(@"第%ld个车主进入停车场",carId);
                [NSThread sleepForTimeInterval:10 + i * 10];
                dispatch_semaphore_signal(semaphore);
                NSLog(@"第%ld个车主离开,有空位了",carId);
            }
        });
    }
}

//运行结果
2018-05-24 12:13:55.959 MultiThreadingDemo[1490:186763] 第3个车主离开,有空位了
2018-05-24 12:13:55.959 MultiThreadingDemo[1490:186860] 第4个车主进入停车场
2018-05-24 12:14:05.959 MultiThreadingDemo[1490:186764] 第1个车主离开,有空位了
2018-05-24 12:14:05.959 MultiThreadingDemo[1490:186861] 第5个车主进入停车场
2018-05-24 12:14:15.960 MultiThreadingDemo[1490:186766] 第2个车主离开,有空位了
2018-05-24 12:14:15.960 MultiThreadingDemo[1490:186862] 第6个车主在规定的时间内等到了车位,进入停车场
2018-05-24 12:14:25.962 MultiThreadingDemo[1490:186862] 第6个车主离开,有空位了
2018-05-24 12:14:25.962 MultiThreadingDemo[1490:186863] 第7个车主进入停车场
2018-05-24 12:14:45.966 MultiThreadingDemo[1490:186860] 第4个车主离开,有空位了
2018-05-24 12:14:45.966 MultiThreadingDemo[1490:186864] 第8个车主进入停车场
2018-05-24 12:14:57.961 MultiThreadingDemo[1490:186865] 第9个车主不等了
2018-05-24 12:15:05.964 MultiThreadingDemo[1490:186861] 第5个车主离开,有空位了
2018-05-24 12:15:05.964 MultiThreadingDemo[1490:186866] 第10个车主进入停车场
2018-05-24 12:15:45.968 MultiThreadingDemo[1490:186863] 第7个车主离开,有空位了
2018-05-24 12:16:15.972 MultiThreadingDemo[1490:186864] 第8个车主离开,有空位了
2018-05-24 12:16:55.971 MultiThreadingDemo[1490:186866] 第10个车主离开,有空位了
GCD系列

参考资料:
https://blog.csdn.net/liuyang11908/article/details/70757534
https://www.jianshu.com/p/2d57c72016c6

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343