方法调整的线程安全性

时间:2013-11-30 16:15:23

标签: objective-c multithreading thread-safety swizzling

方法调配用于以下单例初始化程序,但我不确定调度的线程安全性。

当一个线程要调用一个即将被另一个方法调整的方法时会发生什么? 在任何时候都可以安全地进行调整,而有线程即可调用该方法吗?请回答官方参考。感谢

#import <dispatch/dispatch.h>
#import <objc/runtime.h>

@implementation MySingleton

static MySingleton * __singleton = nil;

+ (MySingleton *) sharedInstance_accessor
{
    return ( __singleton );
}

+ (MySingleton *) sharedInstance
{
    static dispatch_once_t __once = 0;

    dispatch_once( &__once, ^{ 
                __singleton = [[self alloc] init]; 
        Method plainMethod = class_getInstanceMethod( self, @selector(sharedInstance) );
        Method accessorMethod = class_getInstanceMethod( self, @selector(sharedInstance_accessor) );
        method_exchangeImplementations( plainMethod, accessorMethod );
        });
    return ( __singleton );
}

@end

https://gist.github.com/MSch/943369

2 个答案:

答案 0 :(得分:2)

我怀疑有关于此的官方参考,但不需要。

首先,该方法的可执行代码未从内存中取消映射。因此,安装哪个实现并不重要,先前的实现仍然可以执行。

但这确实意味着您必须确保您的数据管理是线程安全的(假设没有人试图直接调用sharedInstance_accessor)。

因此,method_exchangeImplementations()是否是线程安全的问题。 The source说它是(并且它不是之前的几个主要版本),文档也是如此。

正如Brad Allred所说,这不太可能是值得追求的优化。

答案 1 :(得分:1)

根据documentationmethod_exchangeImplementations()是原子的。据推测,这意味着如果在运行method_exchangeImplementations()的同时从另一个线程调用正在交换的两个方法之一,它可能会获得先前的(非交换的)方法,但它不会得到某些东西不一致(例如不会崩溃)。

请注意dispatch_once()是线程安全的,也意味着只要通过+sharedInstance获得对单例实例的所有引用,在完成混合之前,任何线程都不会引用该对象。

最后,我通常不喜欢将这类内容添加到答案中,因为我意识到有时候提问者只是试图更多地了解事情是如何运作的,而不是试图编写生产代码。但是,如果您打算在真实的运输代码中使用它,您应该重新考虑它。调酒往往是一种“糟糕的代码味道”,并且可能有更好的方法来做你想要完成的任何事情(我仍然不清楚)。