2009-10-27 73 views
2

我有我的主应用程序委托,它包含一个返回对象的方法。此应用程序委托在主线程上运行。Objective-C 2.0中的多线程问题

我也有一个NSOperation在不同的线程上运行。除了希望能够在我的主线程上调用我的应用程序委托方法,我还需要从我的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; 
} 

感谢您的帮助!

迈克

回答

11

除非你明确地写代码,以使东西在另一个线程执行,每一个方法调用将被直接线程它被要求执行。方法调用没有魔法。出于线程化目的,您可以将其视为具有与C函数调用完全相同的语义/ ABI。

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

两个不相关的笔记(因为在它这么多人的行程):

  • 声明财产atomic有一点做与线程安全。原子性只能保证你得到一个有效的值,而不是正确的值(这是有区别的)。

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

+0

感谢您有用的答案:-) – 2009-10-27 18:12:28

+1

难道是肯定地说,一个@synchronized(个体经营)锁定的方法{}块会做同样的事情,一个NSLock实例? – 2009-10-29 17:00:14

+0

或多或少;实施细节略有不同,但影响是一样的。 – bbum 2009-11-06 16:21:38

3

你绝对需要在NSOperation线程中执行这个调用,而不是简单地提供所需的对象创建自定义操作的一部分?

如果是这样,我会建议不要使用锁定,除非性能是至关重要的。如果iPhone支持的话,你可以使用大中央调度来获取对象到你的线程:

__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]; 

在主线程实际执行的执行具有较少的隐性风险。

+0

这是一个有趣的方法。我注意到performSelectorOnMainThread方法不允许你返回一个值,但我从来没有想过传递一个指针的地址!出于兴趣,演员*(id *)做了什么?我见过一个类似(NSNumber *)的类型,但我认为id类型不需要指针asterix。什么是第一个asterix? – 2009-10-27 18:14:56

+0

如果你真的想在iPhone上执行blocks/GCD,请查看PLBlocks和WiganWallgate项目。 – nall 2009-10-27 18:47:45

+0

cast'(id *)'确保'-pointerValue'方法返回的'void *'被视为一个指向'id'的指针。第一个'*'将它解引用,以便改变指针的目标而不是指针本身。 – 2009-10-28 02:32:25

2

如果你只需要保护一段关键代码,为什么不使用Objective-C @synchronized指令?当然,使用NSLock也可以,但是你需要明确地管理NSLock实例。从文档:

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

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

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

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

清单12-1使用自

- (void)criticalMethod 
{ 
    @synchronized(self) { 
     // Critical code. 
     ... 
    } 
} 
+0

看起来很有希望。我唯一不明白的是你传递给它的semaphone对象。我没有得到它的用途!? – 2009-10-28 09:38:05