简体   繁体   English

@synchronized和dispatch_async

[英]@synchronized and dispatch_async

What I'm trying to do is to use the @synchronized directive to protect a singleton object from being accessed by multiple threads at once. 我想做的是使用@synchronized指令来保护单个对象不被多个线程一次访问。 I also want to persistently store that singleton object by writing it to disk after each time it's modified, because it is very important that I try as hard as possible not to lose any changes to the object. 我还想通过在每次修改后将其写入磁盘来持久存储该单例对象,因为尽我最大努力不丢失对该对象的任何更改非常重要。

Now I know a lot of you might say don't do that; 现在我知道你们中很多人可能会说不要这样做; it takes too long; 需要太长时间 it's not a good practice, etc., etc. Yes, I am aware of that. 这不是一个好习惯,等等。是的,我知道这一点。 This is more of a "what will happen?" 这更像是“将会发生什么?” question. 题。

So whenever I go to modify the singleton object, I put the modification code inside a @synchronized block and then write the object to disk. 因此,每当我去修改单例对象时,我都会将修改代码放在@synchronized块中,然后将该对象写入磁盘。 A thought I had was to use dispatch_async to do the writing of the object on a separate thread like so: 我当时的想法是使用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];
        });

    }

So my understanding of @synchronized is that only one thread can execute that block of code at a time. 因此,我对@synchronized理解是,一次只有一个线程可以执行该代码块。 My understanding of dispatch_async is a little fuzzy, but I think that this will submit the block to the dispatch queue to be executed asynchronously and return immediately. 我对dispatch_async理解有些模糊,但是我认为这会将块提交到调度队列以异步执行并立即返回。 This means that if another thread comes through my @synchronized block while dataStructure is still being written to disk, it will just submit another block to run and write the newly modified dataStructure to disk, but that won't start until the first dataStructure is written to disk. 这意味着,如果另一个线程来通过我@synchronized块,而dataStructure仍然被写入到磁盘,它只是提出另一块运行并写入新修改的dataStructure到磁盘上,但不会开始,直到第一个dataStructure被写入到磁盘。

Am I thinking about this correctly? 我在想这个吗? Also will setting atomically change to YES or NO or will the serialization of my dispatch queue ensure that multiple threads won't be written to this file at the same time? 还会将原子设置更改为YESNO还是将我的调度队列的序列化确保不会将多个线程同时写入此文件?

Thank you! 谢谢!

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

Dispatch queues themselves are thread safe. 调度队列本身是线程安全的。 In other words, you can submit tasks to a dispatch queue from any thread on the system without first taking a lock or synchronizing access to the queue. 换句话说,您可以从系统上的任何线程将任务提交到调度队列,而无需先获取锁或同步对该队列的访问。

//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];
    });

}

You at least need to synchronise the write on the lock object. 您至少需要同步锁对象上的写入。 This is because the asynchronous block executes outside of the context of the @synchronized{ ... } . 这是因为异步块在@synchronized{ ... }的上下文之外执行。 This means that something else can change the data while it is being written which can lead to a logical inconsistency. 这意味着在写入数据时,其他某些事情可能会更改数据,这可能导致逻辑上的不一致。

You probably also want some mechanism to check if the object has been modified since it was last written. 您可能还需要某种机制来检查对象自上次写入以来是否已被修改。 Otherwise, you'll find yourself doing unnecessary IO operations. 否则,您会发现自己在执行不必要的IO操作。 eg 例如

  • Thread 1 modifies the object and puts a write on the queue. 线程1修改对象并将写入写入队列。
  • Thread 2 modifies the object and puts a write on the queue. 线程2修改对象并将写入写入队列。
  • Thread 1's write saves the mods from thread 1 and thread 2 线程1的写操作保存了线程1和线程2中的mod
  • Thread 2's write saves the mods from thread 1 and thread 2 (which is the same as the last step) 线程2的写操作保存了线程1和线程2中的mod(与最后一步相同)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM