1

I have 2 method calls exposed in my library as follows:

-(void) createFile {
    dispatch_async(serialQueue, ^{
        [fileObj createFile:fileInfo completion:^(void){
           //completion block C1 
        }];
   });
}

-(void) readFile:(NSUInteger)timeStamp {
    dispatch_async(serialQueue, ^{
        [fileObj readFile:timeStamp completion:^(void){
           //completion block C2 
        }];
   });
}

Now the createFile:fileInfo:completion and readFile:timeStamp:completion are in turn XPC calls that call into a process P1. Their implementation inside the process P1 looks like this:

@interface FileObject : NSObject

+ (instancetype) sharedInstance;

@property (nonatomic, strong) NSData *fileContents;

@end

@implementation FileObject

+ (instancetype)sharedInstance
{
    static FileObject *sharedObj = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedObj = [[self alloc] init];
    });
    return sharedObj;
}

- (void)createFile:(FileInfo *)fileInfo
          completion:(void (^))completion {

          FileObject *f = [FileObject sharedInstance];
          //lock?
          f.fileContents = //call some method;
          //unlock         
    }

- (void)readFile:(NSUInteger)timeStamp
      completion:(void (^))completion {

    FileObject *f = [FileObject sharedInstance];

     //do stuff with f.fileContents
}
@end

The point to be noted is that,a call to method createFile is capable of making modifications to the singleton obj and readFile:fileInfo is always called after createFile(serial queue used at invocation).

My question is given the serial queue usage for the two methods exposed in my library,

  1. Do I still need to lock and unlock when I modify f.fileContents in readFileInfo:FileInfo:completion?
  2. How about if multiple different processes call into my library? Will XPC to P1 handle that automatically or should I have to do something about it ?
ExceptionHandler
  • 213
  • 1
  • 8
  • 24

1 Answers1

2

You asked:

Do I need to use locks if the methods are already executed in a serial queue?

If you can interact with non thread-safe objects at the same time from multiple threads, yes, you can use locks (or a variety of other techniques) to synchronize your access. If you're doing all of your interaction from a serial queue, though, no locks are needed.

But you need to be careful because although you're using a serial queue, you've got completion handlers that could be running on different threads. But if you coordinate the interaction on those completion handlers so that none can ever run at the same time (more on that, below), then no locks (or other synchronization techniques) are needed.

A bunch of other thoughts based upon your code snippets (and conversations we've had elsewhere):

  1. You're still using the GCD dispatch calls with asynchronous methods. There's a cognitive dissonance there. Either

    • lose the dispatch queues altogether and use completion handler patterns (this is the better solution IMHO, but you say you can't change your endpoints which apparently precludes this more logical approach); or
    • make createFile and readFile behave synchronously (with semaphores, for example) and then you can take advantage of the GCD queue behaviors (we generally eschew patterns like locks, semaphores, or anything that will "wait", but given that you're doing this on background queue, it's less problematic).
  2. If you want these two fundamentally asynchronous tasks to behave synchronously, you can achieve this with locks, too, but I think dispatch semaphores are more the logical pattern if you're going to use dispatch queues.

  3. The better pattern would be to make createFile and readFile create custom, asynchronous, NSOperation subclasses. This is a much stronger pattern than locks or semaphores in GCD because it minimizes the deadlocking risks.

  4. Completely unrelated to the question here, I would not suggest making FileObject a singleton. Each FileObject is associated with a particular file, and it has no business being a singleton. This is especially important because we discovered offline that you're contemplating this being an XPC service with multiple requests coming in, and the singleton pattern is antithetical to that.

    Plus, as an aside, FileObject doesn't pass the basic criteria for when you'd use singletons. For discussion on the considerations of singletons (which we don't need to repeat here, especially since it's unrelated to your main question), see What is so bad about singletons? Singleton's have their place, but this is a scenario where you likely will want separate instances, so the singleton pattern seems especially ill-suited.

Community
  • 1
  • 1
Rob
  • 415,655
  • 72
  • 787
  • 1,044