@synchronized和dispatch_async

时间:2014-07-03 08:39:34

标签: ios objective-c synchronization dispatch-async

我要做的是使用@synchronized指令来保护单个对象不被多个线程一次访问。我还希望通过在每次修改后将其写入磁盘来持久存储该单例对象,因为尽可能努力不丢失对象的任何更改是非常重要的。

现在我知道很多你可能会说不这样做;这花了太长时间;这不是一个好习惯,等等。是的,我知道这一点。这更像是“将会发生什么?”问题

因此,每当我修改单例对象时,我将修改代码放在@synchronized块中,然后将对象写入磁盘。我的想法是使用dispatch_async在一个单独的线程上写对象,如下所示:

//singleton object
id dataStructure;

@synchronized(lockObject)
    {
        //code that modifies singleton object
        //not important

        //sharedFileQueue is a SERIAL queue
        dispatch_async([self sharedFileQueue], ^(void){
            NSError * err;

            NSData * plist = [NSPropertyListSerialization dataWithPropertyList:dataStructure
                                                      format:NSPropertyListBinaryFormat_v1_0
                                                      options:0 error:&err];

            //url to somewhere
            NSURL * url;
            BOOL success = [plist writeToURL:url atomically:YES];
        });

    }

所以我对@synchronized的理解是,一次只有一个线程可以执行该代码块。我对dispatch_async的理解有点模糊,但我认为这会将块提交给调度队列,以便异步执行并立即返回。这意味着如果另一个线程通过我的@synchronized块,而dataStructure仍在写入磁盘,它将只提交另一个块来运行并将新修改的dataStructure写入磁盘,但是在第一个dataStructure写入磁盘之前不会启动。

我是否正确地考虑过这个问题?还会将原子设置更改为YESNO,或者我的调度队列的序列化是否确保多个线程不会同时写入此文件?

谢谢!

2 个答案:

答案 0 :(得分:0)

https://developer.apple.com/library/ios/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html

Dispatch队列本身是线程安全的。换句话说,您可以从系统上的任何线程向调度队列提交任务,而无需先锁定或同步对队列的访问。

//singleton object
id dataStructure;

@synchronized(lockObject)
{
    //code that modifies singleton object
    //not important

    id dataStructureToWrite = [dataStructure copy];
    //sharedFileQueue is a SERIAL queue
    dispatch_async([self sharedFileQueue], ^(void){
        NSError * err;

        NSData * plist = [NSPropertyListSerialization dataWithPropertyList:dataStructureToWrite
                                                                    format:NSPropertyListBinaryFormat_v1_0
                                                                   options:0 error:&err];

        //url to somewhere
        NSURL * url;
        BOOL success = [plist writeToURL:url atomically:YES];
    });

}

答案 1 :(得分:0)

您至少需要同步锁定对象上的写入。这是因为异步块在@synchronized{ ... }的上下文之外执行。这意味着其他东西可以在写入时改变数据,这可能导致逻辑上的不一致。

您可能还需要一些机制来检查对象自上次写入以来是否已被修改。否则,您将发现自己正在进行不必要的IO操作。例如

  • 线程1修改对象并在队列上写入。
  • 线程2修改对象并在队列上写入。
  • 线程1的写保存来自线程1和线程2
  • 的mod
  • 线程2的写保存来自线程1和线程2的mod(与最后一步相同)