Objective-C 2.0中的多线程问题

时间:2009-10-27 17:48:40

标签: iphone objective-c cocoa multithreading nslock

我的主应用程序委托包含一个返回对象的方法。此应用程序委托在主线程上运行。

我还有一个可以在不同的线程上运行的NSOperation。除了希望能够在我的主线程上调用我的app委托方法之外,我还需要从我的NSOperation线程调用它来获取它返回的对象。我的第一个问题是,如果我从我的其他线程中调用它......

id newObject = [[[UIApplication sharedApplication] delegate] myMethod];

...该方法是否会在与NSOperation相同的线程上处理,还是与应用程序委托所在的线程(主)相同?

我还想确保myMethod中的代码只能由我的操作线程或主线程一次调用一次。我可以在应用程序委托中创建一个NSLock实例var,并执行以下操作:

-(id)myMethod {
    [myLock lock];
    myObject = // Get or create my object to return
    [myLock unlock];
    return myObject;
}

感谢您的帮助!

麦克

3 个答案:

答案 0 :(得分:11)

除非您明确编写代码以使某些内容在另一个线程上执行,否则每个方法调用都将直接在调用它的线程上执行。方法调用没有魔力。您可以将其视为具有与C函数调用完全相同的语义/ ABI以进行线程化。

您的锁定模式可以正常工作,以确保跨线程的独占访问。

另外两个不相关的笔记(因为很多人绊倒了):

  • 将属性声明为atomic与线程安全无关。原子性只保证您获得有效值,而不是正确的值(存在差异)。

  • 自动释放的对象永远不会在线程之间传递。您需要在发送线程上使用显式retain,并在接收线程上使用平衡最终release

答案 1 :(得分:3)

您是否绝对需要在NSOperation线程上执行此调用,而不是仅仅在创建自定义操作时提供所需的对象?

如果是这样,我建议不要使用锁,除非性能至关重要。如果iPhone支持它,您可以使用Grand Central Dispatch将对象放到您的线程上:

__block id newObject = nil;
dispatch_sync(dispatch_get_main_queue(), ^{
    newObject = [[[[UIApplication sharedApplication] delegate] myMethod] retain];
});

对于iPhone,我很想创建一个辅助方法:

- (void)createNewObject:(NSValue *)returnPtr {
    id newObject = [[[[UIApplication sharedApplication] delegate] myMethod] retain];
    *(id *)[returnPtr pointerValue] = newObject;
}

并从NSOperation主题中调用它:

id newObject = nil;
[self performSelectorOnMainThread:@selector(createNewObject:)
                       withObject:[NSValue valueWithPointer:&newObject]
                    waitUntilDone:YES];

实际上在主线程上执行执行的隐含风险较少。

答案 2 :(得分:2)

如果您只需要保护代码的关键部分,为什么不使用Objective-C @synchronized指令?当然,使用NSLock也可以,但是您需要显式管理NSLock实例。来自文档:

Objective-C支持应用程序中的多线程。这意味着两个线程可以尝试同时修改同一个对象,这种情况可能会导致程序出现严重问题。为了保护代码段不被一次多个线程执行,Objective-C提供了@synchronized()指令。

@synchronized()指令锁定一段代码以供单个线程使用。其他线程被阻塞,直到线程退出受保护的代码;也就是说,当执行继续经过@synchronized()块中的最后一个语句时。

@synchronized()指令将任何Objective-C对象作为唯一参数,包括self。此对象称为互斥信号量或互斥量。它允许线程锁定一段代码以防止其他线程使用它。您应该使用单独的信号量来保护程序的不同关键部分。在应用程序变为多线程之前创建所有互斥对象以避免竞争条件是最安全的。

清单12-1显示了一个代码示例,该代码使用self作为互斥锁来同步对当前对象的实例方法的访问。您可以采用类似的方法来同步关联类的类方法,使用Class对象而不是self。当然,在后一种情况下,一次只允许一个线程执行一个类方法,因为只有一个类对象由所有调用者共享。

清单12-1使用self

锁定方法
- (void)criticalMethod
{
    @synchronized(self) {
        // Critical code.
        ...
    }
}