关于GCD信号量dispatch_semaphore_signal

来源:互联网 发布:淘宝联盟登不了怎么办 编辑:程序博客网 时间:2024/06/05 12:40

最近在做一些连接硬件拍照的工作,在iOS设备上控制相机拍照,遇到了一些问题,现记录如下:

下面的两段代码主要功能是:创建一个信号量Semaphore,然后创建一个定时器,每隔一段时间查询相机状态.当相机处理完毕之后,发出信号,继续执行以后的操作.整个过程都是在全局队列中处理的.

- (NSString*)run:(NSString*)command{// Create and keep HTTP sessionNSURLSessionConfiguration* config = [NSURLSessionConfiguration defaultSessionConfiguration];_session= [NSURLSession sessionWithConfiguration:config];_commandId = command;// Semaphore for synchronization (cannot be entered until signal is called)_semaphore = dispatch_semaphore_create(0);// Create and start timerNSTimer *timer = [NSTimer timerWithTimeInterval:0.5ftarget:selfselector:@selector(getState:)userInfo:nilrepeats:YES];NSRunLoop *runLoop = [NSRunLoop currentRunLoop];[runLoop addTimer:timer forMode:NSRunLoopCommonModes];[runLoop run];// Wait until signal is calleddispatch_semaphore_wait(_semaphore, DISPATCH_TIME_FOREVER);return _state;}/*** Delegate called during each set period of time* @param timer Timer*/- (void)getState:(NSTimer*)timer{// Create JSON dataNSDictionary *body = @{@"id": _commandId};// Set the request-body.[_request setHTTPBody:[NSJSONSerialization dataWithJSONObject:body options:0 error:nil]];// Send the url-request.NSURLSessionDataTask* task =[_session dataTaskWithRequest:_requestcompletionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {if (![_state isEqualToString:@"inProgress"]) {dispatch_semaphore_signal(_semaphore);// Stop timer[timer invalidate];}}];[task resume];}

然而,在数据处理完毕,以下代码信号已经发出

dispatch_semaphore_signal(_semaphore);

并且定时器也已经销毁的前提下,dispatch_semaphore_wait竟然不执行!百思不得其解!
最后,还是得求助万能的stackoverflow
这个是类似问题
其中指出:

Most likely you are running out of threads. The dispatch_semaphore_signal(semaphore) , which should release the dispatch_semaphore_wait() needs to be executed in a new thread (see objectForKey:block: for details). If OS fails to dispatch that new thread, you stuck, as nobody will send you the dispatch_semaphore_signal.

How often and when it happens depends on computer/device speed, how fast you scroll the table etc. That’s why you can’t reproduce this issue on your computer.

也就是说,dispatch_semaphore_signal需要在新的线程中执行,否则如果操作系统指派当前线程失败,你就永远收不到它发出的信号.

受此启发,在定时器外层另开一个线程

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{        NSTimer *timer = [NSTimer timerWithTimeInterval:0.5f                                                 target:self                                               selector:@selector(getState:)                                               userInfo:nil                                                repeats:YES];        NSRunLoop *runLoop = [NSRunLoop currentRunLoop];        [runLoop addTimer:timer forMode:NSRunLoopCommonModes];        [runLoop run];    });

问题解决!!!

0 0