目标C等待直到处理了一个暂挂任务 [英] Objective C wait until an asynch task has been processed

查看:77
本文介绍了目标C等待直到处理了一个暂挂任务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的代码中,我正在运行本地服务器(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:

  1. CocoaHTTPServer接收到一个请求,因此创建了一个新线程
  2. 它调用Command类的静态方法来执行请求
  3. Command类创建一个新的命令对象,该对象调用另一个类(使用反射),该类调用ALAsset API,并将命令对象传递给它.
  4. 返回时,ALAsset API调用将调用以下方法的委托方法: 命令类
  1. CocoaHTTPServer receives a request and hence creates a new thread
  2. It calls the static method of a Command class to execute the request
  3. The Command class creates a new command Object calls another class (using reflection) which calls ALAsset APIs and passes the command Object to it
  4. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆