iOS dispatch_semaphore调研

如果你你需要将依赖有限资源的任务提交给dispatchqueue来做,你可能需要管理好这些任务对资源的访问。dispatch_semaphore就是做这个的。因为GCD不需要调用到内核所以它获取信号量用的时间更少,它仅在资源不可达并且系统需要暂停线程的时候需要访问内核。

  1. When you create the semaphore (using the dispatch_semaphore_create function), you can specify a positive integer indicating the number of resources available.

  2. In each task, call dispatch_semaphore_wait to wait on the semaphore.

  3. When the wait call returns, acquire the resource and do your work.

  4. When you are done with the resource, release it and signal the semaphore by calling the dispatch_semaphore_signal function.

For an example of how these steps work, consider the use of file descriptors on the system. Each application is given a limited number of file descriptors to use. If you have a task that processes large numbers of files, you do not want to open so many files at one time that you run out of file descriptors. Instead, you can use a semaphore to limit the number of file descriptors in use at any one time by your file-processing code. The basic pieces of code you would incorporate into your tasks is as follows:

When you create the semaphore, you specify the number of available resources. This value becomes the initial count variable for the semaphore. Each time you wait on the semaphore, the dispatch_semaphore_wait function decrements that count variable by 1. If the resulting value is negative, the function tells the kernel to block your thread. On the other end, the dispatch_semaphore_signal function increments the count variable by 1 to indicate that a resource has been freed up. If there are tasks blocked and waiting for a resource, one of them is subsequently unblocked and allowed to do its work.

 

dispatch_create创建信号量,dispatch_wait信号量减一,如果结果为负数,内核会阻塞线程,dispatch_semaphore_signal增加信号量加1,表示资源释放,如果有任务等待这个资源,他们中的一个就会获取资源继续执行。

例子1

 

- (void)doRegularWork
{
    NSLog(@"%@",NSStringFromSelector(_cmd));
    dispatch_queue_t queue = dispatch_queue_create([@"dispatch_semaphore_test" UTF8String], DISPATCH_QUEUE_CONCURRENT);
    semaphore = dispatch_semaphore_create(1);
    NSMutableArray *array = [NSMutableArray array];
    for (int index = 0; index < 10; index++)
    {
        dispatch_async(queue, ^(){
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            [array addObject:[NSNumber numberWithInt:index]];
            NSLog(@"---%d---:%@", index,[array componentsJoinedByString:@","]);
            dispatch_semaphore_signal(semaphore);
        });
    }
}

 

输出结果

2016-03-27 16:37:36.536 DispatchSemaphoreTest[5744:53215] doRegularWork
2016-03-27 16:37:36.537 DispatchSemaphoreTest[5744:53248] ---0---:0
2016-03-27 16:37:36.537 DispatchSemaphoreTest[5744:53248] ---4---:0,4
2016-03-27 16:37:36.538 DispatchSemaphoreTest[5744:53248] ---6---:0,4,6
2016-03-27 16:37:36.538 DispatchSemaphoreTest[5744:53248] ---8---:0,4,6,8
2016-03-27 16:37:36.538 DispatchSemaphoreTest[5744:53249] ---1---:0,4,6,8,1
2016-03-27 16:37:36.539 DispatchSemaphoreTest[5744:53259] ---5---:0,4,6,8,1,5
2016-03-27 16:37:36.539 DispatchSemaphoreTest[5744:53251] ---2---:0,4,6,8,1,5,2
2016-03-27 16:37:36.540 DispatchSemaphoreTest[5744:53260] ---7---:0,4,6,8,1,5,2,7
2016-03-27 16:37:36.540 DispatchSemaphoreTest[5744:53258] ---3---:0,4,6,8,1,5,2,7,3
2016-03-27 16:37:36.540 DispatchSemaphoreTest[5744:53261] ---9---:0,4,6,8,1,5,2,7,3,9

  

由于是并发异步线程queue执行任务 sempaphore起初初始化就是1,顺利执行,输出结果也可以看出没有index重复。

 

例子2,通过一个semaphore,来控制线程间的通信

 

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController
{
    dispatch_semaphore_t semaphore;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self start];
}

- (void)increaseSemaphre
{
    NSLog(@"%@",NSStringFromSelector(_cmd));
    dispatch_semaphore_signal(semaphore);
}

- (void)start
{
    [self doRegularWork];
    [self performSelector:@selector(increaseSemaphre) withObject:nil afterDelay:1];
}

- (void)doRegularWork
{
    NSLog(@"%@",NSStringFromSelector(_cmd));
    dispatch_queue_t queue = dispatch_queue_create([@"dispatch_semaphore_test" UTF8String], DISPATCH_QUEUE_CONCURRENT);
    semaphore = dispatch_semaphore_create(0);
    NSMutableArray *array = [NSMutableArray array];
    for (int index = 0; index < 10; index++)
    {
        dispatch_async(queue, ^(){
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            [array addObject:[NSNumber numberWithInt:index]];
            NSLog(@"---%d---:%@", index,[array componentsJoinedByString:@","]);
            dispatch_semaphore_signal(semaphore);
        });
    }
}

@end

 输出:

2016-03-27 16:42:05.048 DispatchSemaphoreTest[6076:57699] doRegularWork
2016-03-27 16:42:06.049 DispatchSemaphoreTest[6076:57699] increaseSemaphre
2016-03-27 16:42:06.049 DispatchSemaphoreTest[6076:57734] ---0---:0
2016-03-27 16:42:06.050 DispatchSemaphoreTest[6076:57735] ---1---:0,1
2016-03-27 16:42:06.050 DispatchSemaphoreTest[6076:57733] ---2---:0,1,2
2016-03-27 16:42:06.050 DispatchSemaphoreTest[6076:57748] ---3---:0,1,2,3
2016-03-27 16:42:06.051 DispatchSemaphoreTest[6076:57749] ---4---:0,1,2,3,4
2016-03-27 16:42:06.051 DispatchSemaphoreTest[6076:57750] ---5---:0,1,2,3,4,5
2016-03-27 16:42:06.051 DispatchSemaphoreTest[6076:57751] ---6---:0,1,2,3,4,5,6
2016-03-27 16:42:06.052 DispatchSemaphoreTest[6076:57752] ---7---:0,1,2,3,4,5,6,7
2016-03-27 16:42:06.052 DispatchSemaphoreTest[6076:57753] ---8---:0,1,2,3,4,5,6,7,8
2016-03-27 16:42:06.053 DispatchSemaphoreTest[6076:57754] ---9---:0,1,2,3,4,5,6,7,8,9

  通过以上输出可以观察到semaphore初始化为0,所以第一个异步加入到queue的任务(打印index==0)是不能执行的,

当1秒后semaphore有效了,它才执行,它执行了之后,semaphore又被减为0,后面的任务(打印index==1)又需要等待(index==0)的任务执行完才可以执行。所以会出现上面输出结果中从0到9顺序下来。

 

从以上的输出我们可以推理出一个结论:多个异步任务在等待一个信号量的时候,当一个信号量signal之后,是按照先加入的任务顺序优先满足执行的。

 

 

参考苹果的文档地址:

https://developer.apple.com/library/watchos/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html#//apple_ref/doc/uid/TP40008091-CH102-SW24

posted on 2016-03-27 17:02  wxm5558  阅读(100)  评论(0编辑  收藏  举报