Is it possible to remove dispatch_once in Objective-C++?

前端 未结 2 1605
生来不讨喜
生来不讨喜 2021-01-02 20:54

Since C++11, local static variables are known to be initialized in a thread safe manner (unless the -fno-threadsafe-statics is given), as specified

2条回答
  •  天涯浪人
    2021-01-02 21:50

    Generally, Objective-C++, which allows mixing Objective-C-Objects and code with C++ objects and code, is a different language than "pure" C++11. Therefore, I don't think that everything guaranteed for C++11 is automatically guaranteed in Objectiver-C++'s mixed world. And I have been spending some time now investigating apple's documentation whether specific guarantees on static local variables or even block variables are also given in Objective-C++.

    As I did not find a statement to this, I tried introducing a race condition on the creation of an object, one with the proposed "new style", i.e. using a static local variable, one with the "old style" with dispatch_once, and one "real" race condition "notOnlyOnce" ignoring any synchronization (just to be sure that the code actually introduces a race condition).

    The tests show that both "new style" and "old style" seem to be thread safe, whereas "notOnlyOnce" clearly is not. Unfortunately, such a test could have just proofen that "new style" produces a race condition, but it cannot proof that there will never be a race condition. But as "new style" and "old style" behave the same, but "notOnlyOnce" shows up a race condition in the same setting, we can at least assume that static local variables work as you proposed.

    See the following code and the respective outputs.

    @interface SingletonClass : NSObject
    
    - (instancetype)init;
    
    @end
    
    @implementation SingletonClass
    
    - (instancetype)init {
        self = [super init];
        std::cout << "Created a singleton object" << std::endl;
        for (int i=0; i<1000000; i++) { i++; }
        return self;
    }
    
    @end
    
    @interface TestClassObjCPP : NSObject 
    
    @property (nonatomic) SingletonClass *sc;
    
    + (SingletonClass *)onlyOnceNewStyle;
    + (SingletonClass *)onlyOnceOldStyle: (TestClassObjCPP*)caller;
    + (SingletonClass *)notOnlyOnce: (TestClassObjCPP*)caller;
    
    @end
    
    @implementation TestClassObjCPP
    
    
    + (SingletonClass *)onlyOnceNewStyle {
        static SingletonClass *object = [[SingletonClass alloc] init];
        return object;
    }
    
    + (SingletonClass *)onlyOnceOldStyle: (TestClassObjCPP*)caller {
    
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            caller.sc = [[SingletonClass alloc] init];
        });
    
        return caller.sc;
    }
    
    + (SingletonClass *)notOnlyOnce: (TestClassObjCPP*)caller {
    
        if (caller.sc == nil)
            caller.sc = [[SingletonClass alloc] init];
    
        return caller.sc;
    }
    
    @end
    
    
    int main(int argc, char * argv[]) {
    
    
        @autoreleasepool {
    
            std::cout << "Before loop requesting singleton." << std::endl;
            TestClassObjCPP *caller = [[TestClassObjCPP alloc] init];
            caller.sc = nil;
            for (int i=0; i<10000; i++) {
                dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                    [TestClassObjCPP onlyOnceNewStyle];  // (1)
                    // [TestClassObjCPP onlyOnceOldStyle:caller]; // (2)
                    // [TestClassObjCPP notOnlyOnce:caller]; // (3)
                });
    
            }
            std::cout << "After loop requesting singleton." << std::endl;
    
            return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
        }
    }
    

    Output for onlyOnceNewStyle (1):

    Before loop requesting singleton.
    Created a singleton object
    After loop requesting singleton.
    

    Output for onlyOnceOldStyle (2):

    Before loop requesting singleton.
    Created a singleton object
    After loop requesting singleton.
    

    Output for notOnlyOnce (3):

    Before loop requesting singleton.
    Created a singleton object
    Created a singleton object
    Created a singleton object
    After loop requesting singleton.
    

    So not a clear yes or no, but I hope it helps in some way.

提交回复
热议问题