2

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

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

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

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

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

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

谢谢你的帮助!

麦克风

4

3 回答 3

11

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

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

另外两个不相关的注释(因为有很多人绊倒它):

  • 将属性声明为atomic与线程安全无关。原子性只保证你得到一个有效的值,而不是正确的值(有区别)。

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

于 2009-10-27T17:50:37.847 回答
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];

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

于 2009-10-27T18:06:18.473 回答
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.
        ...
    }
}
于 2009-10-27T19:46:23.417 回答