目标C等待直到处理了一个暂挂任务 [英] Objective C wait until an asynch task has been processed
问题描述
在我的代码中,我正在运行本地服务器(CocoaHTTPServer).当服务器接收到请求时,它会创建一个线程并将控制权传递给某个方法(-(NSObject<HTTPResponse> *)httpResponseForMethod:(NSString *)method URI:(NSString *)path
,在这里可能无关紧要).
In my code, I am running a local server (CocoaHTTPServer). When the server receives a request, it creates a thread and passes control to a certain method ( - (NSObject<HTTPResponse> *)httpResponseForMethod:(NSString *)method URI:(NSString *)path
, perhaps irrelevant here).
我需要阅读本地资产列表并返回结果. API调用([assetsLibrary enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) ...
)是异步的.
I need to read a list of local assets and return the result. The API call ( [assetsLibrary enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) ...
) is asynchronous.
由于HTTPResponse需要等待直到API调用完成,因此我创建了一个名为_isProcessing
的标志,该标志是在进行API调用之前设置的.调用完成后,我将取消设置标志并返回HTTP请求.等待的代码如下:
Since the HTTPResponse needs to wait until the API call has finished, I have created a flag called _isProcessing
, which I set before making the API call. After the call is finished, I am unsetting the flag and returning the HTTP request. The code to wait looks like:
// the API call is non-blocking. hence, wait in a loop until the command has finished
samCommand->isProcessing = YES;
while (samCommand->isProcessing) {
usleep(100*1000);
}
API调用在完成其任务后将调用委托方法,如下所示:
The API call calls a delegate method upon finishing its task as follows:
// to be called at the end of an asynch operation (eg: reading local asset list)
- (void) commandDidFinish {
// flag to open the lock
isProcessing = NO;
}
这可行,但可能需要增强性能.我如何在这里使用任何东西(运行循环等)来改善性能.
This works, but will perhaps require performance enhancements. How can I use anything (run-loop etc) here to improve upon the performance.
按照weichsel的解决方案,我创建了一个信号灯.我的代码顺序是:
Following weichsel's solution, I created a semaphore. The sequence of my code is:
- CocoaHTTPServer接收到一个请求,因此创建了一个新线程
- 它调用Command类的静态方法来执行请求
- Command类创建一个新的命令对象,该对象调用另一个类(使用反射),该类调用ALAsset API,并将命令对象传递给它.
- 返回时,ALAsset API调用将调用以下方法的委托方法: 命令类
- CocoaHTTPServer receives a request and hence creates a new thread
- It calls the static method of a Command class to execute the request
- The Command class creates a new command Object calls another class (using reflection) which calls ALAsset APIs and passes the command Object to it
- Upon returning, the ALAsset API call calls the delegate method of the command class
因此,我将信号灯嵌入了适当的位置.但是,信号量的等待循环有时不会结束.正常输出应为:
I have hence embedded semaphores in appropriate locations. However, the semaphore's wait loop just doesnt end sometimes. The normal output should be:
2014-02-07 11:27:23:214 MM2Beta[7306:1103] HTTPServer: Started HTTP server on port 1978
2014-02-07 11:27:23:887 MM2Beta[7306:6303] created semaphore 0x1f890670->0x1f8950a0
2014-02-07 11:27:23:887 MM2Beta[7306:6303] calling execute with 0x1f890670
2014-02-07 11:27:23:887 MM2Beta[7306:6303] starting wait loop 0x1f890670->0x1f8950a0
2014-02-07 11:27:23:887 MM2Beta[7306:907] calling getAssetsList with delegate 0x1f890670
2014-02-07 11:27:24:108 MM2Beta[7306:907] calling delegate [0x1f890670 commandDidFinish]
2014-02-07 11:27:24:108 MM2Beta[7306:907] releasing semaphore 0x1f890670->0x1f8950a0
2014-02-07 11:27:24:109 MM2Beta[7306:6303] ending wait loop 0x1f890670->0x0
在每几次运行中,最后一步(不会出现ending wait loop 0x1f890670->0x0
).因此,等待循环永远不会结束.有时,代码也会在同一时间崩溃.任何线索,这里出了什么问题.
In every few runs, the last step ( ending wait loop 0x1f890670->0x0
doesnt occur). Hence, the wait loop never ends. Sometimes the code crashes too, exactly at the same point. Any clue what is wrong here.
我的代码如下:
@implementation SAMCommand {
NSData* resultData;
dispatch_semaphore_t semaphore; // a lock to establish whether the command has been processed
}
// construct the object, ensuring that the "command" field is present in the jsonString
+(NSData*) createAndExecuteCommandWithJSONParamsAs:(NSString *)jsonString {
SAMCommand* samCommand = [[SAMCommand alloc] init];
samCommand.commandParams = [jsonString dictionaryFromJSON];
if(COMPONENT==nil || COMMAND==nil){
DDLogError(@"command not found in %@",jsonString);
return nil;
}
samCommand->semaphore = dispatch_semaphore_create(0);
DDLogInfo(@"created semaphore %p->%p",samCommand,samCommand->semaphore);
// to execute a command contained in the jsonString, we use reflection.
DDLogInfo(@"calling execute with %p",samCommand);
[NSClassFromString(COMPONENT) performSelectorOnMainThread:NSSelectorFromString([NSString stringWithFormat:@"%@_%@_%@:",COMMAND,MEDIA_SOURCE,MEDIA_TYPE]) withObject:samCommand waitUntilDone:NO];
// the above calls are non-blocking. hence, wait in a loop until the command has finished
DDLogInfo(@"starting wait loop %p->%p",samCommand,samCommand->semaphore);
dispatch_semaphore_wait(samCommand->semaphore, DISPATCH_TIME_FOREVER);
DDLogInfo(@"ending wait loop %p->%p",samCommand,samCommand->semaphore);
DDLogInfo(@"");
// return the data
return samCommand->resultData;
}
// to be called at the end of an asynch operation (eg: reading local asset list)
- (void) commandDidFinish {
// flag to release the lock
DDLogInfo(@"releasing semaphore %p->%p",self,semaphore);
dispatch_semaphore_signal(semaphore);
semaphore = nil;
}
@end
我可以使用它:)
最后,似乎稳定的工作是创建信号量,并将其传递给ALAsset异步API调用,并在调用结束时将其释放.之前,我在创建信号量的类中调用了委托方法,而信号量对象却以某种方式得到了释放.不确定那里到底发生了什么.
Finally, what seems to work stably is creating the semaphore, and passing it to the ALAsset asynch API calls, and releasing it at the end of the call. Earlier, I was calling a delegate method of the class where I had created the semaphore, and the semaphore object was somehow getting releases. Unsure of what was happening there really.
推荐答案
您可以使用信号量来阻止当前队列的执行,直到另一个队列返回为止.
基本模式是:
You can use semaphore to block execution of the current queue until another one returns.
The basic pattern is:
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
[assetsLibrary enumerateAssetsUsingBlock^(ALAsset *result, NSUInteger index, BOOL *stop):^{
...
dispatch_semaphore_signal(semaphore);
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_release(semaphore);
您可以在Apple的MTAudioProcessingTap Xcode项目中找到此方法的完整示例:
https://developer.apple.com/library/ios/samplecode/AudioTapProcessor
相关行从MYViewController.m:86
You can find a full example of this method in Apple's MTAudioProcessingTap Xcode Project:
https://developer.apple.com/library/ios/samplecode/AudioTapProcessor
The relevant lines start at MYViewController.m:86
这篇关于目标C等待直到处理了一个暂挂任务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!