您的位置:首页 > 移动开发 > IOS开发

关于GCD信号量dispatch_semaphore_signal

2016-10-11 18:57 405 查看
最近在做一些连接硬件拍照的工作,在iOS设备上控制相机拍照,遇到了一些问题,现记录如下:

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

- (NSString*)run:(NSString*)command
{
// Create and keep HTTP session
NSURLSessionConfiguration* 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 timer
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];

// Wait until signal is called
dispatch_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 data
NSDictionary *body = @{@"id": _commandId};

// Set the request-body.
[_request setHTTPBody:[NSJSONSerialization dataWithJSONObject:body options:0 error:nil]];

// Send the url-request.
NSURLSessionDataTask* task =
[_session dataTaskWithRequest:_request
completionHandler:^(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];
});


问题解决!!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ios semaphore gcd