2
- (NSPersistentContainer *)persistentContainer {
    // The persistent container for the application. This implementation creates and returns a container, having loaded the store for the application to it.
    @synchronized (self) {
        if (_persistentContainer == nil) {
            _persistentContainer = [[NSPersistentContainer alloc] initWithName:@"BaseApplication"];
            [_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {
                if (error != nil) {
                    // Replace this implementation with code to handle the error appropriately.
                    // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.

                    /*
                     Typical reasons for an error here include:
                     * The parent directory does not exist, cannot be created, or disallows writing.
                     * The persistent store is not accessible, due to permissions or data protection when the device is locked.
                     * The device is out of space.
                     * The store could not be migrated to the current model version.
                     Check the error message to determine what the actual problem was.
                    */
                    NSLog(@"Unresolved error %@, %@", error, error.userInfo);
                    abort();
                }
            }];
        }
    }

    return _persistentContainer;
}

The code above is generated by Xcode, but I want to know the purpose of using @synchronize(self) and what will happen if we do not use @synchronize(self)? I do know @synchronize(self) is for multi-thread safety. What I want to know is what will happen if two thread invoke loadPersistentStoresWithCompletionHandler method at the same.

wanchen
  • 33
  • 7
  • 3
    It prevents multiple persistent containers from being created if two threads access it at the same time. – dan May 30 '17 at 16:14
  • The `if (_foo == nil) { _foo = ... }` pattern represents a [race condition](https://en.m.wikipedia.org/wiki/Race_condition), whereby if two threads happened to run that code at the same time, it's possible that the they both could pass the `if` test (i.e. first thread is in the process of instantiating the object and second thread passes `if` test before first thread had a chance to update the variable). Also second thread could try to access pointer at exact same time first thread is setting it. The `@synchronized` prevents these issues by ensuring only one thread at a time can run that code. – Rob May 30 '17 at 16:39
  • @dan I do know `@synchronize(self)` is used for multi-thread safety, but I do not know what will happen if two threads access it at the same time ? Thanks again. – wanchen May 31 '17 at 01:22
  • @Rob Thanks for your detailed explanation.I think if we allow two threads to access that code here, we will get the same result.Is that true? If so why we should regard those code as race condition code ? – wanchen May 31 '17 at 01:27
  • You're guaranteed to get the same value only because of the `@synchronized` directive (because it ensures that the second thread will wait for the first one to leave the block). In the absence of that, no guarantee. – Rob May 31 '17 at 01:55
  • @Rob I got it and thank you very much ! – wanchen May 31 '17 at 05:45

0 Answers0