多线程之使用信号量

来源:互联网 发布:java 判断编码格式 编辑:程序博客网 时间:2024/05/21 10:59

引言

信号量作为GCD的一部分,常用于多线程或任务间协作,当一个任务的执行过程中需要依赖另一个任务时即可使用信号量。

实现原理

信号量通过信号计数来实现。其使用即计数过程可分为三个部分:创建信号量、等待信号与释放信号。

  • 创建信号量
    函数为dispatch_semaphore_t dispatch_semaphore_create( long value),可指定信号的初始数量。

  • 等待信号
    函数为dispatch_semaphore_wait( dispatch_semaphore_t dsema, dispatch_time_t timeout),可指定等待的信号量和超时时间。
    每执行一次等待信号,信号数量减1;当结果信号数量大于等于0时直接通过执行后续代码;当信号数量小于0时锁住当前线程,等待信号释放或超时才能执行后续代码。

  • 释放信号
    函数为dispatch_semaphore_signal(dispatch_semaphore_t deem),可指定释放的信号量。
    每次释放信号,该信号量的信号数量加1;此时如有等待信号的线程则可通过继续执行。

信号量的应用

常见的信号量应用模式可以总结为:
1. 用初始信号数量控制并发任务数量
2. 将异步回传方法封装成同步回传方法

这里我们讲一下第二种,定义一个通过计算获取值的类,其对外的函数可以直接返回结算值,而内部的实现则需要调用计算类的计算方法并通过代理方法返回结果。
这种情况下,可以在对外的函数实现内锁住线程等待信号,并在回调函数内获取计算值释放信号,然后再从对外函数里返回值。
代码如下:

//定义头文件@protocol IPZCallBackProtocol <NSObject>-(void) returnValue:(NSString *)value;@end@interface IPZSemaphoreTest : NSObject<IPZCallBackProtocol>-(NSString *) getValueByExcute;@end
//实现类#import "IPZSemaphoreTest.h"#import "IPZAsyncExcuteObject.h"@implementation IPZSemaphoreTest{    dispatch_semaphore_t _sem;    dispatch_queue_t _queue;    NSString *_value;}-(NSString *)getValueByExcute{    if (_sem==nil) {        _sem=dispatch_semaphore_create(0);        _queue=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);    }    dispatch_async(_queue, ^{        IPZAsyncExcuteObject *excuteObject=[IPZAsyncExcuteObject new];        excuteObject.delegate=self;        [excuteObject excute];    });    dispatch_semaphore_wait(_sem, DISPATCH_TIME_NOW);    return _value;}-(void)returnValue:(NSString *)value{    _value=value;    dispatch_semaphore_signal(_sem);}@end

需要注意的是,在主线程中调用等待信号会造成主线程阻塞,如果释放信号也在主线程进行则APP会直接卡死。
建议另起线程使用信号量。

0 0